Mengacu pada Alias ​​Kolom dalam Klausa WHERE

166
SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
WHERE daysdiff > 120

saya mendapat

+ msgstr "nama kolom hari tidak valid".

Maxlogtm adalah bidang datetime. Hal-hal kecil yang membuatku gila.

pengguna990016
sumber
tidak yakin untuk mysql, tapi mungkin alias perlu dibungkus dengan ticks `daysdiff`.
Ash Burlaczenko

Jawaban:

194
SELECT
   logcount, logUserID, maxlogtm,
   DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
WHERE ( DATEDIFF(day, maxlogtm, GETDATE() > 120)

Biasanya Anda tidak bisa merujuk ke alias bidang dalam WHEREklausa. (Anggap saja sebagai keseluruhan SELECTtermasuk alias, diterapkan setelah WHEREklausa.)

Tapi, seperti yang disebutkan dalam jawaban lain, Anda bisa memaksa SQL untuk memperlakukan SELECTagar ditangani sebelum WHEREklausa. Ini biasanya dilakukan dengan tanda kurung untuk memaksakan urutan operasi logis atau dengan Common Table Expression (CTE):

Parenthesis / Subselect:

SELECT
   *
FROM
(
   SELECT
      logcount, logUserID, maxlogtm,
      DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
   FROM statslogsummary   
) as innerTable
WHERE daysdiff > 120

Atau lihat jawaban Adam untuk versi CTE yang sama.

Jamie F
sumber
16
Ini tidak mungkin secara langsung, karena secara kronologis, DI MANA terjadi sebelum SELECT, yang selalu merupakan langkah terakhir dalam rantai eksekusi. REFER - stackoverflow.com/questions/356675/…
david blaine
afaik jika alias dalam pemilihan adalah subquery berkorelasi ini akan berfungsi sementara solusi CTE tidak.
Răzvan Flavius ​​Panda
Seperti yang disebutkan Pascal dalam jawabannya di sini stackoverflow.com/a/38822328/282887 , Anda dapat menggunakan klausa HAVING yang tampaknya bekerja lebih cepat daripada subqueries.
Bakhtiyor
@ Bakhtiyor HAVINGJawabannya tidak berfungsi di sebagian besar lingkungan SQL, termasuk MS-SQL yang menjadi pertanyaan. (Dalam T-SQL, HAVINGmembutuhkan fungsi agregat.)
Jamie F
72

Jika Anda ingin menggunakan alias dalam WHEREklausa Anda, Anda harus membungkusnya dalam sub pilih, atau CTE :

WITH LogDateDiff AS
(
   SELECT logcount, logUserID, maxlogtm
      , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
   FROM statslogsummary
)
SELECT logCount, logUserId, maxlogtm, daysdiff
FROM LogDateDiff
WHERE daysdiff > 120
Adam Wenger
sumber
2
Apakah Anda tahu cara ini menunjukkan efisiensi? Apakah ada overhead tambahan menggunakan CTE?
James
5
CTE hanyalah sintaks yang lebih cantik untuk sub-kueri, sehingga kinerjanya akan sama dengan itu. Dalam pengalaman saya, perbedaan kinerja bukanlah sesuatu yang membuat saya khawatir untuk operasi seperti ini, tetapi harus cukup sederhana untuk mengujinya di lingkungan Anda untuk melihat apakah tabel / kueri spesifik Anda terpengaruh dengan ini vs memanggil keluar rumus khusus di mana klausa. Saya curiga Anda tidak akan melihat perbedaan.
Adam Wenger
CTE sangat bagus sampai Anda mencoba menggunakannya sebagai subquery. Saya harus menggunakan untuk membuat mereka sebagai pandangan untuk membuat sarang mereka. Saya menganggap ini kelemahan serius SQL
symbiont
10

Cara paling efektif untuk melakukannya tanpa mengulangi kode Anda adalah menggunakan HAVING dan bukannya WHERE

SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary
HAVING daysdiff > 120
Pascal
sumber
1
Saya pikir menggunakan HAVINGalias tidak standar (itu berfungsi pada MySQL, meskipun). Secara khusus, saya pikir itu tidak berfungsi dengan SQL Server.
tokland
2
SQL Server:[S0001][207] Invalid column name 'daysdiff'
Vadzim
3
SQL Server:[S0001][8121] Column 'day' is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.
Vadzim
9

Jika Anda tidak ingin membuat daftar semua kolom Anda di CTE, cara lain untuk melakukannya adalah dengan menggunakan outer apply:

select
    s.logcount, s.logUserID, s.maxlogtm,
    a.daysdiff
from statslogsummary as s
    outer apply (select datediff(day, s.maxlogtm, getdate()) as daysdiff) as a
where a.daysdiff > 120
Roman Pekar
sumber
6

Bagaimana dengan menggunakan subquery (ini bekerja untuk saya di Mysql)?

SELECT * from (SELECT logcount, logUserID, maxlogtm
   , DATEDIFF(day, maxlogtm, GETDATE()) AS daysdiff
FROM statslogsummary) as 'your_alias'
WHERE daysdiff > 120
Shekhar Joshi
sumber
4

HAVING berfungsi di MySQL sesuai dengan dokumentasi:

The HAVING klausa ditambahkan ke SQL karena keyword WHERE tidak dapat digunakan dengan fungsi agregat.

roier.rdz
sumber
4

Anda bisa merujuk ke alias kolom tetapi Anda harus mendefinisikannya menggunakan CROSS/OUTER APPLY:

SELECT s.logcount, s.logUserID, s.maxlogtm, c.daysdiff
FROM statslogsummary s
CROSS APPLY (SELECT DATEDIFF(day, s.maxlogtm, GETDATE()) AS daysdiff) c
WHERE c.daysdiff > 120;

Demo DBFiddle

Pro:

  • definisi tunggal ekspresi (lebih mudah dipertahankan / tidak perlu disalin-tempel)
  • tidak perlu untuk membungkus seluruh permintaan dengan CTE / luar
  • kemungkinan untuk merujuk WHERE/GROUP BY/ORDER BY
  • kemungkinan kinerja yang lebih baik (eksekusi tunggal)
Lukasz Szozda
sumber
1
nilainya untuk menyebutkan bahwa itu hanya bekerja di SQL Server
Martin Zinovsky
1
@MartinZinovsky Pertanyaan ditandai dengan sql-serverdan t-sql:)
Lukasz Szozda
0

Datang ke sini mencari sesuatu yang mirip dengan itu, tapi dengan KASUS sebuah KAPAN, dan berakhir dengan menggunakan tempat seperti ini: WHERE (CASE WHEN COLUMN1=COLUMN2 THEN '1' ELSE '0' END) = 0mungkin Anda bisa menggunakan DATEDIFFdalam WHERElangsung. Sesuatu seperti:

SELECT logcount, logUserID, maxlogtm
FROM statslogsummary
WHERE (DATEDIFF(day, maxlogtm, GETDATE())) > 120
Scy
sumber