WHERE yan tümcesinde referans takma adı (SELECT'te hesaplanır)


130
SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
WHERE BalanceDue > 0 --error

Seçilen sütunlar listesinde bir değişken olarak ayarlanan hesaplanan 'BalanceDue' değeri, WHERE yan tümcesinde kullanılamaz.

Yapabileceği bir yol var mı? Bu ilgili soruda ( MySQL Select İfadesinde bir Değişken Kullanarak Bir Where Maddesinde ), cevap aslında hayır gibi görünüyor, hesaplamayı iki kez yazarsınız ( ve bu hesaplamayı sorguda gerçekleştirirsiniz), hiçbiri ki bu tatmin edici.

Yanıtlar:


237

ORDER BY haricinde bir diğer ada başvuramazsınız çünkü SELECT, değerlendirilen ikinci son cümledir. İki geçici çözüm:

SELECT BalanceDue FROM (
  SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
  FROM Invoices
) AS x
WHERE BalanceDue > 0;

Ya da sadece ifadeyi tekrarlayın:

SELECT (InvoiceTotal - PaymentTotal - CreditTotal) AS BalanceDue
FROM Invoices
WHERE  (InvoiceTotal - PaymentTotal - CreditTotal)  > 0;

İkincisini tercih ederim. İfade son derece karmaşıksa (veya hesaplaması maliyetliyse), bunun yerine muhtemelen hesaplanan (ve belki de kalıcı olan) bir sütunu düşünmelisiniz, özellikle de birçok sorgu aynı ifadeye başvuruyorsa.

PS korkularınız temelsiz görünüyor. En azından bu basit örnekte, SQL Server, iki kez referans vermiş olsanız bile hesaplamayı yalnızca bir kez gerçekleştirecek kadar akıllıdır. Devam edin ve planları karşılaştırın; aynı olduklarını göreceksiniz. İfadenin birden çok kez değerlendirildiğini gördüğünüz daha karmaşık bir durumunuz varsa, lütfen daha karmaşık sorguyu ve planları gönderin.

Tam olarak aynı yürütme planını veren 5 örnek sorgu aşağıda verilmiştir:

SELECT LEN(name) + column_id AS x
FROM sys.all_columns
WHERE LEN(name) + column_id > 30;

SELECT x FROM (
SELECT LEN(name) + column_id AS x
FROM sys.all_columns
) AS x
WHERE x > 30;

SELECT LEN(name) + column_id AS x
FROM sys.all_columns
WHERE column_id + LEN(name) > 30;

SELECT name, column_id, x FROM (
SELECT name, column_id, LEN(name) + column_id AS x
FROM sys.all_columns
) AS x
WHERE x > 30;

SELECT name, column_id, x FROM (
SELECT name, column_id, LEN(name) + column_id AS x
FROM sys.all_columns
) AS x
WHERE LEN(name) + column_id > 30;

Beş sorgunun tümü için sonuç planı:

görüntü açıklamasını buraya girin


11
Vay. SQL Server, hesaplamayı yalnızca bir kez yapacak kadar akıllı
alternatefaraz

5
Vay canına, bu çok kaliteli bir cevap!
Siddhartha

Bir MERGE ifadesinde bazı ekstra koşullara ihtiyacım vardı ve bunu çalıştırabilmemin tek yolu buydu. Teşekkürler!
Eric Burdo

1
@EricBurdo kullanıyorsanız MERGE, lütfen tüm bunları dikkate aldığınızdan emin olun: MERGEdikkatli olun .
Aaron Bertrand

11

Bunu kullanarak yapabilirsiniz cross apply

SELECT c.BalanceDue AS BalanceDue
FROM Invoices
cross apply (select (InvoiceTotal - PaymentTotal - CreditTotal) as BalanceDue) as c
WHERE  c.BalanceDue  > 0;

4

Hem SELECT, WHERE hem de diğer tümceciklerde kullanılabilen bir değişkeni etkili bir şekilde tanımlamak aslında mümkündür.

Çapraz birleştirme, başvurulan tablo sütunlarına uygun bağlanmaya mutlaka izin vermez, ancak OUTER APPLY bunu yapar - ve nullları daha şeffaf olarak ele alır.

SELECT
    vars.BalanceDue
FROM
    Entity e
OUTER APPLY (
    SELECT
        -- variables   
        BalanceDue = e.EntityTypeId,
        Variable2 = ...some..long..complex..expression..etc...
    ) vars
WHERE
    vars.BalanceDue > 0

Syed Mehroz Alam'a şeref .

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.