multipleselect – sql update
- simPod
- Člen | 383
mam ve formulari multiple select, kazda jeho polozka ma nejakou id hodnotu
kdyz jich vyberu vic, jak ma vypadat db update
statement po
odeslani formulare? potrebuji do databaze do kolonky vlozit hodnoty 1 a 2 tak,
aby sly nasledne pouzit v where IN()
(where IN(1,2)
)
diky
Editoval simPod (8. 5. 2012 17:36)
- vvoody
- Člen | 910
Absolutne som nepochopil co chces dosiahnut, skus to napisat ludskou recou ;) ak ide len o WHERE IN() tak v dokumentacii je:
$table->where("field", array(1, 2)); //Means field IN (1, 2)
- jtousek
- Člen | 951
Nette\Database\Selection má metodu update, takže totéž jakobys ty řádky selectoval (druhá tabulka, čtvrtý řádek) a za to připojíš ten ->update(…).
Nauč se hledat. ;-)
EDIT: Hele ty chceš možná něco jinýho… nebude lepší ty záznamy smazat a přidat? Typicky jich bude jiný počet než předtím.
Editoval jtousek (8. 5. 2012 18:30)
- simPod
- Člen | 383
2jtousek: to neni ono
zkusim to jeste takhle:
CREATE TABLE IF NOT EXISTS `column` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`value_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
ve formulari je multiselect
$form->addMultiSelect('select', 'Multiselect', array(1=>'prvni',2=>'druha')
vyberu v multiselectu vsechny polozky a odeslu
formular $form->onSuccess[] = callback($this, 'submitFce');
function submitFce($form){
$values= $form->values;
$this->context->myModel->updateTable($values->select);
}
Model
...
function updateTable($value){
$this->conn->table('column')->update(array(
'value_id' => $value
))
}
...
a tady to je: promenna $value
muze obsahovat 2,3 nebo
i 20 idcek, viz hodnota z multiselect
jak je vlozim do DB? A jak je tam vlozim tak, aby pak slo v pohode
pouzit ->where(array($value))
je to jasnejsi?
diky
- vvoody
- Člen | 910
ten formular sa v produkcii bude viacnasobne odosielat a takymto sposobom chces len zaznamenavat pocet kolko krat ktore pole bolo odoslane? Vies, neviem v akom kontexte chces to ->where(array($value)) pouzit.
Kazdopadne pre vkladanie do tabulky pouzi insert ;)
function updateTable($values){
foreach($values as $value){
$this->conn
->table('column')
->insert(array(
'value_id' => $value
));
}
}
Neviem ako presne na multiple insert, teraz trosku typujem
function updateTable($values){
$data = array();
foreach($values as $value){
$data[] = array('value_id'=>$value);
}
$this->conn->table('column')->($data);
}
ale potom by som tu metodu nevolal update ale insert :)
- jtousek
- Člen | 951
Ta SQL tabulka je zcela zřetelně špatně navržená pro to co chceš. Mohl bys upřesnit, jaká data se do té tabulky ukládají, co reprezentují ty řádky, co se vybírá v tom multiselectu a tak? Bez toho ti těžko řeknu jak ta tabulka (či tabulky) má vypadat.
EDIT: Znovu – DELETE a INSERT:
function updateTable($id,$values){
$this->conn->table('column')->where('id',$id)->delete();
foreach ($values as $value) {
$this->conn->table('column')->insert(array('id' => $id, 'value_id' => $value));
}
}
EDIT2: Tohle samozřejmě nemůže fungovat protože id je primární klíč – ta tabulka bude muset být jiná, pravděpodobně se rozloží na dvě nebo primární klíč budou oba dva sloupce.
Editoval jtousek (8. 5. 2012 23:22)
- jtousek
- Člen | 951
Takže jsem to typoval správně. :-) Tohle je klasická relace M:N, která se řeší pomocí 3 tabulek:
- tabulka produktů
- tabulka kategorií
- tabulka vztahů produkt-kategorie, kde máš sloupce např. product_id a category_id + složený primární klíč (PK jsou oba sloupce)
Takže potom jak jsem řekl. Z té vztahové tabulky smažeš všechny výskyty, kde product_id je id produktu se kterým pracuješ. Následně vložíš zcela nové vztahové řádky, pro každou kategorii jeden.
EDIT: Podle tohoto vlákna zatím NDB neumí pracovat s vícesloupcovými PK, takže ta vztahová tabulka bude vypadat asi jako id, product_id, category_id, kde id bude PK, auto increment, ale vlastně se nebude reálně vůbec používat.
Editoval jtousek (9. 5. 2012 11:22)
- jtousek
- Člen | 951
V té vztahové tabulce bude product_id nastaven jako foreign key na products.id a obdobně category_id FK na category.id.
Dále pokud vybíráš dle $id tak nemusíš používat where, stačí get (a už pak nevoláš fetch). Navíc typicky nechceš id jedné kategorie, ale chceš iterovat přes všechny (může jich být i 0!).
foreach($this->conn->table('products')->get($productId)->related('product_category') as $product_category) {
doSomething($product_category->category->id);
}
EDIT: Hlavně si uvědom, že nepracuješ s ID jedné kategorie ale s nějakou množinou – ta kategorie může být jedna, ale taky jich může být deset nebo třeba žádná. Funkce typu getCategoryId tedy nedává žádný smysl, když už tak něco jako getCategories.
EDIT2: Samozřejmě můžeš vyžadovat, že každý produkt spadá do alespoň jedné kategorie – to už ale je na pravidlech jaká si nastavíš pro formulářové prvky a na integritních omezeních v databázi.
Editoval jtousek (9. 5. 2012 12:05)
- simPod
- Člen | 383
aha. to je pro me neco noveho, foreign keys jsem neznal… kazdopadne se mi tedy povedlo prekopat celou strukturu, ted jeste musim neco udelat s temi sql prikazy…
rekneme, ze jsem volal neco takovehleho:
//prezenter
$this->context->myModel->getProducts()->where('category_id', $id);
/*****/
//model
function getProducts() {
return $this->connection->table('products')->order('product_name');
}
tam asi budu muset zacti z druhe strany od kategorii ze? zkusil jsem v modelu tohle:
//prezenter
$products = $this->context->productModel->getProductsByCategory($cat);
foreach($products as $product){
echo $product->products->product_name;
}
//model
function getProductsByCategory($id) {
return $this->connection->table('categories')->get($id)->related('product_category');
}
ale vraci mi to
No reference found for $product_category->products.
jinak spojovaci tabulka vypada takhle:
CREATE TABLE IF NOT EXISTS `product_category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` int(11) NOT NULL,
`category_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `category_id` (`category_id`),
KEY `product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=4939 ;
--
-- Constraints for dumped tables
--
--
-- Constraints for table `product_category`
--
ALTER TABLE `product_category`
ADD CONSTRAINT `product_category_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`product_id`),
ADD CONSTRAINT `product_category_ibfk_2` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`);
diky
- jtousek
- Člen | 951
pk = primary key
fk = foreign key
Ta chyba reference not found znamená že to nenašlo referenci (fk) pro „products“.
Nejsem si teď jistý podle čeho se vyhodnocuje název té reference – buď se ořízne to _id, pak by to bylo „product“, nebo se použije název tabulky, pak by to bylo „products“. Ta druhá varianta mi ale nedává smysl, protože mohu mít dva fk různého významu do jedné tabulky. Takže si myslím, že správná reference je právě jen „product“ a ne „products“.
Editoval jtousek (9. 5. 2012 19:18)
- simPod
- Člen | 383
ano, myslel jsem model
a pak jeste jedna vec: jak na ordering?
function getProductsByCategory($id) {
$array = array();
$query = $this->connection->table('categories')->get($id)->related('product_category');
foreach ($query as $row) {
$row = $row->product;
array_push($array, $row);
}
return ksort($array);
}
a chci vysledek seradit treba podle nazvu
produktu: products.product_name
EDIT: resp. jak na to zavolat napr. limit()
,
order()
, where('published',1)
dik
Editoval simPod (9. 5. 2012 20:24)
- simPod
- Člen | 383
diky to funguje.
je nejaky jednodussi zpusob jak na vysledku udelat neco ve stylu
order()
?
ja si vsechny rows nahazel do array
a pak to rovnam pres
usort
, ktery volam skrz tridu, abych mu mohl predat dalsi
parametry. je to komplikovanejsi, funguje to, ale asi jedinne reseni (?)
- simPod
- Člen | 383
no, tim seradim jen kategorie
ted delam tohle:
//Model
function getProductsByCategory(...){
$array = array();
foreach ($this->connection->table('categories')->where('id', $id)->order('product_price') as $query) {
$query = $query->related('product_category');
foreach ($query as $row) {
$row = $row->product;
array_push($array, $row);
}
}
usort($array, array(new CmpClass($order), "call"));
}
//class
class CmpClass extends ProductModel {
private $order;
function __construct($order) {
$this->order = $order;
}
function call($a, $b) {
return $this->cmp($a, $b, $this->order);
}
function cmp($a, $b, $order) {
return strcmp($b[$order[0]], $a[$order[0]]);
}
}