MyTQL

2014-12-15 9 views
7

'daki bir TRIGGER içinden LAST_INSERT_ID() öğesini değiştirme Bir sütunun (id_2) AUTO_INCREMENT değerini hesaplamak için kullanılan bir BEFORE INSERT TRIGGER var.MyTQL

id_1 | id_2 | data 
1 | 1 | 'a' 
1 | 2 | 'b' 
1 | 3 | 'c' 
2 | 1 | 'a' 
2 | 2 | 'b' 
2 | 3 | 'c' 
2 | 4 | 'a' 
3 | 1 | 'b' 
3 | 2 | 'c' 

PRIMARY (id_1, id_2) sahibim ve InnoDB kullanıyorum. Daha önce, tablo MyISAM kullanıyordu ve hiçbir sorunum olmadı: id_2AUTO_INCREMENT olarak ayarlandı, bu nedenle id_1 için her yeni girdi, yeni id_2 kendi başına üretecektir. Şimdi, InnoDB geçtikten sonra, ben de aynı şeyi yapmak için bu tetikleyici vardır: hariç

SET @id = NULL; 
SELECT COALESCE(MAX(id_2) + 1, 1) INTO @id FROM tbl WHERE id_1 = NEW.id_1; 
SET NEW.id_2= @id; 

Bu mükemmel çalışıyor şimdi LAST_INSERT_ID() yanlış değerini (0 döndürür) sahiptir. Çok fazla kod, LAST_INSERT_ID()'un doğruluğuna bağlıdır. Ancak, MySQL 5.0.12'den beri TRIGGERS içinde LAST_INSERT_ID'a yapılan tüm değişiklikler global değeri etkilememektedir. Bunu atlamanın bir yolu var mı? Ben kolayca LAST_INSERT_ID(NEW.id_2) arayarak LAST_INSERT_ID değiştirir AFTER UPDATE TRIGGER ayarlayabilirsiniz, ancak herhangi bir istemci tarafı içine değiştirildi LAST_INSERT_ID durumunu korumak için MySQL zorlamak için herhangi bir işçi etrafında çalışma var mı 0.

için LAST_INSERT_ID set alacağı Tetik? Herhangi bir alternatif var mı, bu kutuyu destekleyen veya başka bir SELECT max(id_2) FROM tbl WHERE id_1 = :id çalıştıran MyISAM'a geri dönmek, daha önce eklenen satırın bulunacağından emin olmak için işlemin bir parçası olarak mı?

> SHOW CREATE TABLE tbl; 

CREATE TABLE `tbl` (
    `id_1` int(11) NOT NULL, 
    `id_2` int(11) NOT NULL, 
    `data` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 
    PRIMARY KEY (`id_1`,`id_2`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

Örnek: İlk deyim tabloya satır 1 | 4 | 'd' ekleyecektir

INSERT INTO tbl (id_1, id_2, data) VALUES (1, NULL, 'd'); 
SELECT LAST_INSERT_ID(); 

. İkinci deyim 0 döndürecek, ancak 4 dönmek için gerekiyor. ürün içeriyor ben sepetleri içeren bir tablo var ve başka bir tablo (tbl) sahip

:

sistemi hakkında kısa bir açıklama ekleyerek, Ravinder Reddy tarafından sorulan gibi

. sepgesi sepgesi, uygulama tarafından oluşturulur ve sepetler tablosunda AUTO_INCREMENT numarasına bir kimlik atar. Görev, numaralı öğelerini sepetinize = id_1 numaralı sepete tbl ekleyerek bu sepetin kapsamına benzersiz bir kimlik atamaktır. Her ürün ürünle ilişkili data ürününün, aynı sepeti numaralı ürünün içinde tekrarlanmasına gerek yoktur. Pratikte, tüm data girişlerini tek bir sepeti içinde depolamaya çalışıyorum ve daha sonra bu tek girişleri id_1 - id_2 çiftlerine başvurabilir (ve alabilir).

+1

Biraz kafam karışık, ama INSERT uygulanmış bir LAST_INSERT_ID() _before_ nasıl olurdu? LAST_INSERT_ID() öğesinin yalnızca bir istemci aynı istemci bağlantısı üzerinde yürütüldüğünde güvenilir olduğuna inanıyorum. Uygulama bir bağlantıyı açarsa, bir ekleme gerçekleştirir ve bağlantıyı kapatırsa, yeni bir bağlantı açamayacağınız ve bu bağlantıyı gerçekten çağırmadan önce bu bağlantıya bir ekleme yapmadan LAST_INSERT_ID() öğesine erişemeyeceğiniz anlamına gelir. –

+0

INSERT tamamlandıktan sonra, Tetikleyiciyi çalıştırdıktan sonra LAST_INSERT_ID() işlevini çağırıyordum. Diğer bir deyişle, iki sütunlu birincil anahtarın ikinci sütununun değerini üretmek için tetikleyici, yeni ayarlanan değeri iletmenin bir yolu yoktu. Bu soruya bir örnek ekledim. – Xeos

+0

@Xeos: Yayına "show create table tbl" gösterisini ekleyebilir misiniz? –

cevap

1

Tablo yapısı açıklamanızla, değerleri otomatik olarak oluşturulabilen bir birincil anahtar alanına sahip olmadığı açıktır. MySQL'in information_schema.tables, auto_increment tanımlı olmayan alanlar için auto_increment değerini değil null değerini tutmaz.

Tetik sorunu: tetik vücutta kullanılan

kod bloğu id alanları için açık hesaplama ve giriş bağlı görünüyor. Bir auto_increment alanının varsayılan davranışını kullanmadı. MySQL's documentation on LAST_INSERT_ID uyarınca

:

LAST_INSERT_ID() bir BIGINT işaretsiz bir (64-bit) değeri
başarıyla AUTO_INCREMENT kolon için eklenen ilk otomatik olarak değeri temsil
döner

En son yürütülen INSERT ifadesinin bir sonucu olarak .

O alanlar sadece AUTO_INCREMENT için olduğu açıktır.
auto_increment ve id_1 ve id_2 alanlarından hiçbiri atfedilmemiştir.
Nedeni nedeniyle, eklerken bu alanlar için girdi olarak null geçirdiğinizde, hiçbir değer otomatik olarak oluşturulur ve bunlara atanmaz.

masanız bu id_x alanlardan birine auto_increment ayarlamak için Alter ve sonra değerleri ekleme başlayın. Bir uyarı, ekleme sırasında auto_increment alanına açıkça bir değer iletilmesinin last_insert_id'un zero veya en son otomatik olarak oluşturulan değer döndürmesine neden olmasıdır, ancak NEW.id. Ekleme sırasında null geçişi veya auto_increment alanını seçmemek, o alan için YENİ değer üretmeyi tetikleyecektir ve last_insert_id onu seçip iade edebilir.

ardından örnek davranışı yukarıda gösterir:

mysql> drop table if exists so_q27476005; 
Query OK, 0 rows affected, 1 warning (0.00 sec) 

mysql> create table so_q27476005(i int primary key); 
Query OK, 0 rows affected (0.33 sec) 

ardından ifadesi bir alan için bir sonraki uygulanabilir auto_increment değerini gösterir.

mysql> select auto_increment 
    -> from information_schema.tables 
    -> where table_name='so_q27476005'; 
+----------------+ 
| auto_increment | 
+----------------+ 
|   NULL | 
+----------------+ 
1 row in set (0.00 sec) 

bize alana bir null değer ekleme deneyelim. girdi bir not null primary key alanına oldu ama auto_increment için atfedilen çünkü deyimi Üstü

mysql> insert into so_q27476005 values(null); 
ERROR 1048 (23000): Column 'i' cannot be null 

başarısız oldu. Sadece auto_increment alanları için null girişlerini iletebilirsiniz.

Şimdi bize last_insert_id davranışını görelim:

mysql> insert into so_q27476005 values(1); 
Query OK, 1 row affected (0.04 sec) 

mysql> select last_insert_id(); 
+------------------+ 
| last_insert_id() | 
+------------------+ 
|    0 | 
+------------------+ 
1 row in set (0.00 sec) 

giriş açık ve aynı zamanda saha auto_increment için atfedilen değil olduğu gibi last_insert_id için
çağrısı 0 sonuçlandı.Aynı veritabanı bağlantı oturumunda başka bir tablo, başka bir tablo için başka bir insert çağrı başka bir varsa, bu, başka bir değer olabilir unutmayın.

Tablodaki kayıtları görelim.

mysql> select * from so_q27476005; 
+---+ 
| i | 
+---+ 
| 1 | 
+---+ 
1 row in set (0.00 sec) 

Şimdi, bu alanda i için auto_increment uygulayalım. Şu beyan

mysql> alter table so_q27476005 change column i i int auto_increment; 
Query OK, 1 row affected (0.66 sec) 
Records: 1 Duplicates: 0 Warnings: 0 

alanda i için bir sonraki uygulanabilir auto_increment değerini gösterir.

mysql> select auto_increment 
    -> from information_schema.tables 
    -> where table_name='so_q27476005'; 
+----------------+ 
| auto_increment | 
+----------------+ 
|    2 | 
+----------------+ 
1 row in set (0.00 sec) 

Sen last_insert_id hala aynı olup olmadığını kontrol geçebilir.

mysql> select last_insert_id(); 
+------------------+ 
| last_insert_id() | 
+------------------+ 
|    0 | 
+------------------+ 
1 row in set (0.00 sec) 

bize alanına i içine null değer alınır edelim.
mysql> insert into so_q27476005 values(null); 
Query OK, 1 row affected (0.03 sec) 

Bu alan auto_increment için atfedilen çünkü null bir primary key alanına geçen rağmen başarılı oldu.
Hangi değerin oluşturulduğunu ve eklendiğini görelim.

mysql> select last_insert_id(); 
+------------------+ 
| last_insert_id() | 
+------------------+ 
|    2 | 
+------------------+ 
1 row in set (0.00 sec) 

Ve bu alanda i için bir sonraki uygulanabilir auto_increment değerdir:

Şimdi
mysql> select auto_increment 
    -> from information_schema.tables 
    -> where table_name='so_q27476005'; 
+----------------+ 
| auto_increment | 
+----------------+ 
|    3 | 
+----------------+ 
1 row in set (0.00 sec) 

mysql> select * from so_q27476005; 
+---+ 
| i | 
+---+ 
| 1 | 
| 2 | 
+---+ 
2 rows in set (0.00 sec) 

, açık giriş alanı için verildiğinde nasıl last_insert_id sonuç bize gözlemlemek edelim.

mysql> insert into so_q27476005 values(3); 
Query OK, 1 row affected (0.07 sec) 

mysql> select * from so_q27476005; 
+---+ 
| i | 
+---+ 
| 1 | 
| 2 | 
| 3 | 
+---+ 
3 rows in set (0.00 sec) 


mysql> select last_insert_id(); 
+------------------+ 
| last_insert_id() | 
+------------------+ 
|    2 | 
+------------------+ 
1 row in set (0.00 sec) 

Sen last_insert_id nedeniyle açık girişine değerini yakalamak olmadığını görebiliriz.
Ancak, bilgi şeması bir sonraki uygulanabilir değere kayıtlı.

mysql> select auto_increment 
    -> from information_schema.tables 
    -> where table_name='so_q27476005'; 
+----------------+ 
| auto_increment | 
+----------------+ 
|    4 | 
+----------------+ 
1 row in set (0.08 sec) 

Şimdi, alan için giriş/örtük oto olduğunda bizi nasıl last_insert_id sonuç gözlemlemek edelim.

mysql> insert into so_q27476005 values(null); 
Query OK, 1 row affected (0.10 sec) 

mysql> select last_insert_id(); 
+------------------+ 
| last_insert_id() | 
+------------------+ 
|    4 | 
+------------------+ 
1 row in set (0.00 sec) 

Umut, bu ayrıntılar size yardımcı olur.

+0

Böyle detaylı açıklamalar için teşekkür ederiz. 'Id_2' sütununu otomatik artışa ayarlamakla ilgili bir sorun yaşıyorum. Hata Kodu: 1075'i alıyorum. Yanlış tablo tanımı; sadece bir tane otomatik sütun olabilir ve bir anahtar olarak tanımlanmalıdır. Benim durumum, 'id_1' değerini (uygulama tarafından tanımlanan) biliyorum, ama ben id_2'ün değerini bilmiyorum. Yani her bir 'id_1' için, 'id_2' otomatik artışına ihtiyacım var. Yani numarasına istediğim sütun otomatik artışla "id_2". – Xeos

+0

Hata mesajı oldukça açık. Tablo başına yalnızca bir * 'auto_increment' * alanınız olabilir. Sorunuzu yeni bir gönderi olarak yeniden çizmenizi öneririm. gerçekten ne istediğini açıkla. –

+0

Bu tabloyu kullanan soruyu sisteme kısa bir açıklama ekledim. – Xeos