Soru MySQL - Bir tablonun id alanında bir karşılığı olmayan numaraların listesinden seçim yapın


Sayıların bir listesini aldım, {2,4,5,6,7} deyin Ben de dahil olmak üzere bir masa, foos.ID, diyorum, {1,2,3,4,8,9}

Numaralarımın listesini almak ve masamın ID alanındaki bir karşılığı olmayanları bulmak istiyorum.

Bunu başarmanın bir yolu, kimlik alanında {2,4,5,6,7} yüklü bir tablo çubuğu oluşturmak olabilir. Sonra yapardım

SELECT barlar. * BARLARDAN LEFT JOIN foos ON bars.ID = foos.ID foos.ID NULL IS NULL

Ancak, bu sans temp tablosu yapmak istiyorum.

Nasıl olabileceğine dair herhangi bir girişi var mı?


36
2017-11-07 21:00


Menşei


Yukarıdaki örnekte 5 ve 6'yı almalısınız, değil mi? - Sunny Milenov
Evet, 5,6,7'yi arıyorum. Üzgünüm, bunu buraya koymak istedim. - SocialCensus


Cevaplar:


Bu oldukça yaygın olan bir sorundur: bir tablo oluşturmadan anında bir ilişki oluşturmak. Bu sorun için SQL çözümleri oldukça garip. Türetilmiş bir tabloyu kullanan bir örnek:

SELECT n.id
FROM
  (SELECT 2 AS id 
   UNION SELECT 3 
   UNION SELECT 4 
   UNION SELECT 5 
   UNION SELECT 6 
   UNION SELECT 7) AS n
  LEFT OUTER JOIN foos USING (id)
WHERE foos.id IS NULL;

Fakat bu çok iyi ölçeklenmez, çünkü sadece altı yerine birçok değeriniz olabilir. Biriyle uzun bir liste oluşturmak yorucu olabilir UNION değer başına gerekli.

Diğer bir çözüm ise, on basamaklı genel amaçlı bir tabloyu korumak ve birden fazla amaç için tekrar tekrar kullanmaktır.

CREATE TABLE num (i int);
INSERT INTO num (i) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);

SELECT n.id
FROM 
  (SELECT n1.i + n10.i*10 AS id
   FROM num AS n1 CROSS JOIN num AS n10
   WHERE n1.i + n10.i*10 IN (2, 3, 4, 5, 6, 7)) AS n
  LEFT OUTER JOIN foos USING (id)
WHERE foos.id IS NULL;

Bu durum için gerekli olmasa bile iç sorgu oluşturma değerlerini 0..99'dan gösteriyorum. Ancak listenizde 10'dan büyük değerler olabilir. Önemli olan bir masa ile numBiriyle çok uzun zincirlere başvurmadan büyük sayılar üretebilirsiniz UNION değer başına. Ayrıca, istenen değerlerin listesini tek bir yerde belirtebilirsiniz, ki bu daha kullanışlı ve okunabilir.


32
2017-11-07 21:31



Ne yazık ki, kullanılan rakamlar boyut ve aralıkta keyfi. Bu senin ikinci seçeneğini yasaklıyor. Birincisi biraz kludgy ama aynı zamanda, bir tablo olmadan ilişkilerin yaratılması, ulustaki en güzel şey değil. Bazı set-tabanlı mantığa ulaşmayı umuyordum, ama mysql'in SET'i zayıf görünüyor. - SocialCensus
Bu çözüm benim için çalıştı. Yinelenen değerlerle uğraşıyorsanız kullanın union all select. - Seabass
8 yıl sonra bu dava hala bir sorun :). - zozo


Geçici bir tablo kullanmayan kesin sorununuz için bir çözüm bulamıyorum, ancak bir birleştirmenin yerine bir alt seçim kullanarak sorgunuzu yapmanın alternatif bir yolu:

SELECT bars.* FROM bars WHERE bars.ID NOT IN (SELECT ID FROM foos)

Aslen yazdığım diğer posterler gibi:

SELECT * FROM foos WHERE foos.ID NOT IN (2, 4, 5, 6, 7)

ama sonra bunun istediğin şeyin tam tersini ürettiğini fark ettim.


20
2017-11-07 21:11



Evet, temp tablosu gitmenin yolu. Ve haklısın - okumak için çok hızlıdık :) Teşekkürler, mesajımı siliyorum. - Sunny Milenov
Çok kötü, Id temp bir tablo oluşturmak değil ... Ancak, en iyi bahis gibi görünüyor. Teşekkürler! - SocialCensus


PHP kullanıyorsanız, herhangi bir geçici tablo oluşturmadan çalışabilirsiniz.

SELECT ID FROM foos WHERE foos.ID IN (2, 4, 5, 6, 7)

İstediğiniz sonuca dönüştürmek için PHP'nin array_diff () işlevini kullanabilirsiniz. Listeniz (2,4,5,6,7) $ listesi adı verilen bir dizide ise ve yukarıdaki sorgunun sonucu bir dizi $ sonucundaysa o zaman

$no_counterparts = array_diff($list, $result);

... tablonuzdaki tüm sayıları veritabanı tablonuzda karşılıksız olarak döndürecektir. Bu çözüm, sorgudaki tüm işlemi gerçekleştirmezken, PHP'de yapmanız gereken işlem sonrası, istediğiniz şeyi almak için minimumdur ve geçici bir tablo oluşturmaktan kaçınmak yararlı olabilir.


6
2018-05-04 23:36





Benzer bir problemim vardı. Otomatik artırıcı birincil anahtarın bazı eksik değerleri olduğu bir aralık vardı, bu yüzden önce kaç tane olduğunu buldum: select count(*) from node where nid > 1962. Bu sayıyı en yüksek değere göre karşılaştırdığımızda, eksik olan numarayı aldım. Sonra bu sorguyu çalıştırdım: select n2.nid from node n1 right join node n2 on n1.nid = (n2.nid - 1) where n1.nid is null and n2.nid > 1962 Bu ardışık olmayan eksik kayıtların sayısını bulacaktır. Ardışık olanları göstermeyecek ve bunun nasıl yapılacağından emin değilim, daha büyük bir enlem elde etmek için ON yan tümcesini değiştirmenin ötesinde (JOIN tablosunu büyük ölçüde daha büyük hale getirecektir). Her halükarda, bu, toplam yedi kayıptan beş sonuç verdi ve diğer ikisinin de beşten en az birinin yanında olması garanti edildi. Daha büyük bir numaranız eksikse, muhtemelen eksik olanı bulmanın başka bir yoluna ihtiyacınız olacaktır.


1
2018-04-21 14:02





Alnitak (ve sizinki) çözüm işe yarayacak ve sadece SQL dilinde çalışabilen başka bir şey hakkında bir şey yapamam.

Ama burada soru geliyor - değerlerin listesini nasıl geçiyorsunuz? Bunu çağrı kodunda ele almak daha iyi değil - yani ID'leri isteyin ve bu tür manipülasyonlar için daha uygun bir dilde olabilen toplama kodunda karşılaştırın.


0
2017-11-07 21:30