MySQL sorgusunun WHERE yan tümcesinde sütun takma adını kullanmak hata üretir


202

Çalıştırdığım sorgu aşağıdaki gibidir, ancak bu hatayı alıyorum:

# 1054 - 'IN / ALL / ANY alt sorgusundaki' guaranteed_postcode 'bilinmeyen sütunu

SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE `guaranteed_postcode` NOT IN #this is where the fake col is being used
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)

Benim sorum: Neden aynı DB sorgusunun nerede yan tümcesinde sahte bir sütun kullanamıyorum?

Yanıtlar:


434

Sütun takma adlarını yalnızca GROUP BY, ORDER BY veya HAVING yan tümcelerinde kullanabilirsiniz.

Standart SQL, bir WHERE yan tümcesinde bir sütun takma adına başvurmanıza izin vermez. WHERE kodu yürütüldüğünde sütun değeri henüz belirlenemediği için bu kısıtlama uygulanır.

MySQL belgelerinden kopyalandı

Yorumlarda belirtildiği gibi, HAVING kullanmak işi yapabilir. Yine de bu WHERE vs HAVING bir okuma emin olun .


1
Hızlı ve doğru yanıt için şerefe! HAVING yan tümcesine bir göz attım ve başarıyla bu sorguyu çalıştırmak için bir yol çalıştı. Tekrar teşekkürler.
James

39
Kimsenin benimle aynı problu olması durumunda, takma col'u başarısız olan bir yerde kullanıyordu - 'NEREYİ' takas etmek için 'hemen düzeltti +1 iyi cevap.
megaSteve4 28:12

@ megaSteve4 Aynı sorunu yaşadım! "HAVING" kullanarak sorunsuz bir şekilde çözdü. :)
Johan

9
Bu sizin durumunuzda önemli olabilir veya olmayabilir, ancak HAVINGdaha yavaş WHERE
yürütülür

1
Bunun nedeni having, sütun değerlerinin, aldığınız zamana kadar hesaplanması gerektiğidir having. whereYukarıda belirtildiği gibi durum böyle değildir .
Millie Smith

24

Victor'un işaret ettiği gibi, sorun takma addadır. Ancak, ifadeyi doğrudan WHERE x IN y yantümcesine koyarak bu önlenebilir:

SELECT `users`.`first_name`,`users`.`last_name`,`users`.`email`,SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE SUBSTRING(`locations`.`raw`,-6,4) NOT IN #this is where the fake col is being used
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)

Ancak, alt sorgunun dış sorgunun her satırı için yürütülmesi gerektiğinden, bu çok verimsiz olduğunu tahmin ediyorum.


1
@rodion, Evet bu olduğuna inanıyoruz ciddi yavaş ve verimsiz.
Pacerier

20

Standart SQL (veya MySQL), WHERE yan tümcesinde sütun takma adlarının kullanılmasına izin vermez,

WHERE deyimi değerlendirildiğinde, sütun değeri henüz belirlenmemiş olabilir.

( MySQL belgelerinden ). WHERE yan tümcesinde sütun değerini hesaplamak, değeri bir değişkene kaydetmek ve alan listesinde kullanmaktır. Örneğin bunu yapabilirsiniz:

SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
@postcode AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE (@postcode := SUBSTRING(`locations`.`raw`,-6,4)) NOT IN
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)

Bu, karmaşık hale geldiğinde ifadenin tekrarlanmasını önler ve kodun bakımını kolaylaştırır.


9
Bu , "Genel bir kural olarak, hiçbir zaman bir kullanıcı değişkenine değer atamamalı ve aynı ifadedeki değeri okumamalısınız. Beklediğiniz sonuçları alabilirsiniz, ancak bu garanti edilmez." ?
Arjan

Bu kesinlikle akılda tutulması gereken bir şey. Benim için her zaman işe yaradı, bir ifadenin farklı bölümlerinin değerlendirme sırasının düzeltilmesi gerektiğini düşünüyorum (önce NEREDE, sonra SEÇ, sonra GRUPLA, ...) ama bunun için bir referansım yok
Joni

Birkaç örnek: bazıları onlar için MySQL 5.5'te çalıştığını iddia ediyor select @code:=sum(2), 2*@code, ancak benim için 5.6'da ikinci sütun ilk çağırmada NULL veriyor ve tekrar çalıştırıldığında önceki sonucun 2 katı döndürüyor . İlginç bir şekilde, hem seçmek @code:=2, 2*@codeve select @code:=rand(), 2*@codebenim 5.6 (bugün) iş gibi görünüyor. Ama bunlar gerçekten SELECT yan tümcesinde yazma ve okuma; sizin durumunuzda NEREDE ayarlıyorsunuz.
Arjan

@Joni, Neden sadece durumu iki kez değerlendirmiyorsun? Şüphesiz MySQL bunu optimize edecek kadar zekidir .......
Pacerier

@Pacerier özellikle karmaşıksa ifadeyi tekrarlamak zorunda kalır. MySQL'in ortak alt ifade eliminasyonunu uygulayıp uygulamadığını doğrulayamadım.
Joni

16

Belki cevabım çok geç ama bu başkalarına yardımcı olabilir.

Başka bir select deyimiyle içine alabilir ve where deyimini kullanabilirsiniz.

SELECT * FROM (Select col1, col2,...) as t WHERE t.calcAlias > 0

calcAlias ​​hesaplanan takma ad sütunudur.


Güzel ve kısa, ama bu yararlı olamayacak kadar belirsiz.
Agamemnus

@Agamemnus, Bununla ne demek istiyorsun?
Pacerier

Soru, "Neden aynı DB sorgusunun nerede yan tümcesinde sahte bir sütun kullanamıyorum?" Bu cevap bu soruya cevap vermiyor ve bir fiil eksik.
Agamemnus

Daha sonra HAVING
Hett

8

SELECT yantümcesini SELECT alanları ve takma adlarında hesaplanan filtre için kullanabilirsiniz


@ fahimg23 - Emin değilim. Bir sebep bulmaya çalıştım ama yapamıyorum! Bununla birlikte, WHEREve arasındaki farkları unutmayın HAVING. Aynı değiller. stackoverflow.com/search?q=where+vs+having
rinogo

GÜNCELLEME: Bunun nedeni, bu yanıtın aynı çözümü sağlaması ancak daha fazla bilgi içermesidir.
rinogo

1

MySQL 5.5.24 kullanıyorum ve aşağıdaki kod çalışır:

select * from (
SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
) as a
WHERE guaranteed_postcode NOT IN --this is where the fake col is being used
(
 SELECT `postcode` FROM `postcodes` WHERE `region` IN
 (
  'australia'
 )
)

0

Standart SQL, bir WHERE yan tümcesinde sütun takma adlarına yapılan başvurulara izin vermez. Bu kısıtlama, WHERE yan tümcesi değerlendirildiğinde, sütun değeri henüz belirlenmemiş olabileceği için uygulanır. Örneğin, aşağıdaki sorgu geçersizdir:

KİMLİĞİ SEÇ, SAYI (*) tbl_name TARAFINDAN ASLA cnt> 0 GROUP BY id;


0

Koşulların olduğu durumlarda SUBSTRING ( locations. raw, -6,4) kullanabilirsiniz

SELECT `users`.`first_name`, `users`.`last_name`, `users`.`email`,
SUBSTRING(`locations`.`raw`,-6,4) AS `guaranteed_postcode`
FROM `users` LEFT OUTER JOIN `locations`
ON `users`.`id` = `locations`.`user_id`
WHERE SUBSTRING(`locations`.`raw`,-6,4) NOT IN #this is where the fake col is being used
(
SELECT `postcode` FROM `postcodes` WHERE `region` IN
(
 'australia'
)
)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.