Nette Database: insert…select
- Leinad
- Člen | 23
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:
- Jdu na to správně, nebo je nějaký lepší způsob než použití takhle Insert…select?
- 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
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);
}
?>
- Leinad
- Člen | 23
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
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
- ViPEr*CZ*
- Člen | 817
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
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;