Neden bir FROM yan tümcesi eksik olan bu sorgu hata vermiyor?


9

Yani içinde bir yazım hatası olan bir alt sorgu ile bir sorgu var. FROM yan tümcesi eksik. Ama çalıştırdığınızda, hata yapmaz! Neden!?


SELECT

    1
   ,r.id
   ,'0D4133BE-C1B5-4141-AFAD-B171A2CCCE56'
   ,GETDATE()
   ,1
   ,'Y'
   ,'N'
   ,oldItem.can_view
   ,oldItem.can_update

FROM Role r

JOIN RoleObject oldReport
    ON r.customer_id = oldReport.customer_id

JOIN RoleItem oldItem
    ON oldReport.id = oldItem.role_object_id
        AND r.id = oldItem.role_id

WHERE r.id NOT IN (SELECT
        role_id
    WHERE role_object_id = '0D4133BE-C1B5-4141-AFAD-B171A2CCCE56')

AND oldReport.id = '169BA22F-1614-4EBA-AF45-18E333C54C6C'

Yanıtlar:


21

Bu beyan yasaldır (başka bir deyişle hayır FROMgerekli değildir):

SELECT x = 1;
SELECT x = 1 WHERE 1 = 1; -- also try WHERE 1 = 0;

İşin püf noktası, açıkça var olmayan bir sütun adı girdiğiniz zamandır. Yani bunlar başarısız:

SELECT name WHERE 1 = 1;

SELECT x = 1 WHERE id > 0;

Msg 207, Seviye 16, Durum 1
Geçersiz sütun adı 'ad'.
Msg 207, Seviye 16, Durum 1
Geçersiz sütun adı 'id'.

Ancak, geçersiz sütun bir alt sorgu gibi bir şeyde tanıtıldığında, SQL Server'ın bu sorguyu alt sorgunun iç kapsamında bulamadığında yaptığı şey, bir dış kapsama çapraz olur ve alt sorguyu bu dış kapsamla ilişkili hale getirir. Bu, tüm satırları döndürür, örneğin:

SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE 1 = 1);

Çünkü aslında şöyle diyor:

SELECT * FROM sys.columns WHERE name IN (SELECT sys.columns.name WHERE 1 = 1); /*
              ^^^^^^^^^^^                       -----------
                   |                                 |
                   -----------------------------------    */

WHEREAlt sorguda bir maddeye bile ihtiyacınız yoktur :

SELECT * FROM sys.columns WHERE name IN (SELECT name);

Gerçekten dış kapsamdaki tabloya baktığını görebilirsiniz, çünkü bu:

SELECT * FROM sys.columns WHERE name IN (SELECT name WHERE name > N'x');

Çok daha az satır döndürür (sistemimde 11).

Bu kapsam belirleme konusundaki standarda bağlı kalmayı içerir. İki #temp tablonuz olduğunda da benzer şeyler görebilirsiniz:

CREATE TABLE #foo(foo int);
CREATE TABLE #bar(bar int);

SELECT foo FROM #foo WHERE foo IN (SELECT foo FROM #bar);

Hiçbir olduğundan Açıkçası, bu doğru, hata gerektiğini foode #bar? Hayır! Ne oluyor SQL Server diyor ki, "ah, fooburada bir tane bulamadım , diğeri demek zorundasın."

Ayrıca, genel olarak, kaçınırdım NOT IN. NOT EXISTSbazı senaryolarda daha verimli olma potansiyeline sahiptir, ancak daha da önemlisi, hedef sütunun olması mümkün olduğunda davranışı değişmez NULL. Daha fazla bilgi için bu gönderiye bakın .


Yığın Taşması ile ilgili bir soru sordum, cevabın esasen aynı olduğu (sizinki daha kapsamlı olmasına rağmen). Sorgulanan tablonun bir parçası olmayan bir sütuna (soldaki işlenen olarak) başvurmak neden EXISTS işlecinde bir hata değil?
Marc 233

2

Bunu 2016 yılında basitleştirilmiş bir örnekle çoğalttım:

declare @t1 table (c1 int, c2 int, c3 int)
insert into @t1 values (1,2,3), (2,3,4), (3,4,5)

select * from @t1
where
    c1 not in 
    (select c2 where c3 = 3)

Her satır için c2 ve c3'ün değerlendirildiği görülmektedir.


1

SQL Server SELECT sözdiziminde FROM bölümü gerekmez. FROM'u atlarsanız, select deyimi bir satırı olan ve sütun içermeyen "kukla" tablosunu kullanır. Yani

select 'x' as c where ...

ifade true olursa bir satır döndürür ve false olduğunda satır içermez.


Ama sadece bir dış nesnede yoksa select cve cyoksa , bu işe yaramaz . Ben kabul FROMgerekmez, ancak açıkça bir sütun ad koyarken burada oyundaki mekaniği yapar sen değil bir sütun için bir sabit sağlamadıkları takdirde bir dış kapsamında mevcut bir kukla tabloda daha kesinlikle farklıdır ve Varsa, bir çalışma zamanı hatası alırsınız, bu yüzden orada kukla tablo yok. Kukla tablo diğer senaryolarda devreye girebilir, ancak başvuru bir alt sorgu / türetilmiş tablodayken kullanılamaz.
Aaron Bertrand

Örnekte, ilişkili bir alt seçimdir, role_id ve role_object_id, dış seçimdeki tablolardan birine aittir.
Piotr

Doğru, ama söylemek SELECT 'x' AS c, az önce söylenen OP'lerden tamamen farklı bir senaryodur SELECT c. Bir alt sorgu / türetilmiş tabloda.
Aaron Bertrand
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.