Nette Database: insert…select

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Leinad
Člen | 23
+
0
-

Chci vložit do tabulky nový záznam, kdy nový záznam bude mít articleId o jedno větší, než je aktuálně nejvyšší. Rozhodl jsem se na to použít dotaz ve stylu

INSERT INTO news SELECT MAX(id)+1 AS id, MAX(articleId)+1 AS articleId, 'cz', 'novy-clanek', '2012-10-12', 0, 'Nový článek', '', 'Nový text článku' FROM news

Struktura tabulky je následující. id je unikátní, ale articleId je stejný pro různé překlady jednoho článku. Z toho důvodu potřebuji někdy jen zkopírovat, ale někdy vytvořit nové articleId.

CREATE TABLE `news` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `articleId` int(11) NOT NULL,
  `lang` char(5) COLLATE utf8_czech_ci NOT NULL,
  `address` varchar(255) COLLATE utf8_czech_ci NOT NULL,
  `date` date NOT NULL,
  `visible` tinyint(4) NOT NULL,
  `title` varchar(255) COLLATE utf8_czech_ci NOT NULL,
  `image` varchar(255) COLLATE utf8_czech_ci NOT NULL,
  `text` text COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `articleId_lang` (`articleId`,`lang`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;

Zkouším v Nette Database následující příkaz:

<?php
public function insertNew($data){
		// funkce, co mi dá default za chybějící předaná $data;
		$data = $this->fillData($data);

		$selection = $this->getTable();
		foreach($data As $key => $value){
			if($key == "id") {
				$selection->select("MAX(id)+1 AS id");
			} elseif($key == "articleId") {
				$selection->select("MAX(articleId)+1 AS articleId");
			} else {
				$selection->select($this->getDatabase()->quote($value) . " AS $key");
			}
		}

		// JDE TOHLE TO? Nebo musím napsat jako SQL dotaz?
		return $this->getTable()->insert($selection);
	}
?>

Dotazy:

  1. Jdu na to správně, nebo je nějaký lepší způsob než použití takhle Insert…select?
  2. Pokud jdu na to správně, umožňuje Nette Database skládat dotazy výše naznačeným způsobem a jen používám špatné příkazy, nebo to není možné a musím si to skládat jako SQL string?

2.a) Pokud to není možné v Nette Database, je to možné v Dibi?

Leinad
Člen | 23
+
0
-

5 dní bez odpovědi :-(

Nakonec jsem to udělal takto, na půl SQL a na půl Nette Database:

<?php
	public function insertNew($data){
		$data = $this->fillData($data);
		$bindValues = array();

		$selection = $this->getTable();
		foreach($data As $key => $value){
			if($key == "id") {
				$selection->select("MAX(id)+1 AS id");
			} elseif($key == "articleId") {
				$selection->select("MAX(articleId)+1 AS articleId");
			} else {
				$selection->select("? AS $key");
				$bindValues[] = $value;
			}
		}

		return $this->getDatabase()->queryArgs("INSERT INTO " . $this->getTableName() . " " . $selection->getSql(), $bindValues);
	}
?>
ViPEr*CZ*
Člen | 817
+
0
-

Proč tam je toto MAX(id)+1, když id je AUTO_INCREMENT ???
Proč takto počítáte articleId? Jestli jsem to dobře pochopil, tak articleId je nějaký idéčko co se pak používá v jiný tabulce (překladů), tak použijte cizý klíče.

Leinad
Člen | 23
+
0
-

Chtěl jsem, aby se u „id“ použil autoincrement, ale nevěděl jsem jak na to. Díky za upozornění, ono tam vlastně stačí dát NULL a díky tomu se vygeneruje sám.

No, nad tím jsem taky přemýšlel, udělat jako dvě tabulky. Ale aktuálně by vypadaly asi takto:

CREATE TABLE `news2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;


CREATE TABLE `newsLang` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `news2_id` int(11) NOT NULL,
  `lang` char(5) COLLATE utf8_czech_ci NOT NULL,
  `address` varchar(255) COLLATE utf8_czech_ci NOT NULL,
  `date` date NOT NULL,
  `visible` tinyint(4) NOT NULL,
  `title` varchar(255) COLLATE utf8_czech_ci NOT NULL,
  `image` varchar(255) COLLATE utf8_czech_ci NOT NULL,
  `text` text COLLATE utf8_czech_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `articleId_lang` (`news2_id`,`lang`),
  CONSTRAINT `newsLang_ibfk_1` FOREIGN KEY (`news2_id`) REFERENCES `news2` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;

což jsem se trochu bál, že mi zbytečně ztíží programování. Zase je pravda, že je to asi lepší řešení pro budoucnost, kdybych se náhodou rozhodl dát více věcí, co budou společné pro oba jazyky článku.

ViPEr*CZ*
Člen | 817
+
0
-

No AUTO INCREMENT se použije automaticky… prostě při insertu nenastavíte žádnou hodnotu (ani to NULL) a mysql server se o dopočítání postará. Dvě tabulky propojené přes klíče jsou rozhodně lepší. Ono už to dopočítávání je složité :-). Mrkněte na dokumentaci

Leinad
Člen | 23
+
0
-

No, při insertu, kde vyjmenuju sloupce kromě toho „id“, tak to dosadí samo. Ale i při insertu, kde se berou automaticky všechny sloupce? Nenahlásil by mi ten dotaz, že počet sloupců ze SELECT je menší, než kolik očekává INSERT?

ViPEr*CZ*
Člen | 817
+
0
-

Leinad napsal(a):

No, při insertu, kde vyjmenuju sloupce kromě toho „id“, tak to dosadí samo. Ale i při insertu, kde se berou automaticky všechny sloupce? Nenahlásil by mi ten dotaz, že počet sloupců ze SELECT je menší, než kolik očekává INSERT?

Teď to nějak nechápu? Nechápu kde se tam bere SELECT?

Leinad
Člen | 23
+
0
-

Předchozí řešení, kde jsem používal MAX pro articleId byl zapsaný jako:

INSERT INTO tabulka SELECT MAX(id)+1, sloupec2, sloupec3, MAX(articleId)+1, sloupec5;

resp.

INSERT INTO tabulka SELECT NULL, sloupec2, sloupec3, MAX(articleId)+1, sloupec5;

Ten dotaz se neprovede, když vynechám první záznam, kde je id, co je autoincrement ne?

INSERT INTO tabulka SELECT sloupec2, sloupec3, MAX(articleId)+1, sloupec5;
vvoody
Člen | 910
+
0
-

Co takto vymenovat stlpce?

INSERT INTO tabulka (stlpec2,stlpec3,...) SELECT stlpec2, stlpec3...
Leinad
Člen | 23
+
0
-

vvoody napsal(a):

Co takto vymenovat stlpce?

INSERT INTO tabulka (stlpec2,stlpec3,...) SELECT stlpec2, stlpec3...

Jj, viz výše, vyjmenovat sloupce nebo použít ten null (o kterém jsem původně nevěděl)