ทำไมฉันไม่สามารถใช้คำสั่ง CASE เพื่อดูว่ามีคอลัมน์อยู่หรือไม่และไม่ได้เลือกคอลัมน์


17

ทำไมบางอย่างเช่นนี้จึงไม่ทำงาน

SELECT
CASE 
WHEN NULLIF(COL_LENGTH('Customers', 'Somecol'), '') IS NULL THEN NULL
ELSE Somecol
END AS MyTest
FROM Customers;

ฉันแค่ตรวจสอบว่ามีคอลัมน์อยู่อย่างไรก็ตาม SQL Server บ่นว่าSomecolไม่มีอยู่ มีทางเลือกอื่นสำหรับสิ่งนี้ในข้อความเดี่ยว?


3
คุณมีตัวอย่างสำหรับเหตุผลที่คุณต้องการทำสิ่งนี้หรือไม่? ฉันไม่เข้าใจว่าทำไมคุณต้องการเขียนแบบสอบถามที่พยายามเลือกจากคอลัมน์ที่อาจไม่มีอยู่
Mark Sinkinson

4
SQL Server ประเมินว่าไวยากรณ์คำสั่งของคุณถูกต้องก่อนที่จะดำเนินการ ดังนั้นคอลัมน์ทั้งหมดที่อ้างอิงจะต้องมีอยู่ในตารางแม้ว่าจะถูกห่อในCASEคำสั่ง
Mark Sinkinson

@MarkSinkinson: ชื่อจะถูกตรวจสอบหลังจากไวยากรณ์ แต่ใช่แล้ว SQL Server จะทำเช่นนั้นก่อนที่จะเรียกใช้ชุดงานจริง
Andriy M

1
การเลือกจากINFORMATION_SCHEMAสามารถใช้เป็นวิธีแก้ปัญหาได้
Brilliand

คำตอบ:


43

แบบสอบถามต่อไปนี้ใช้ความคิดเช่นเดียวกับในคำตอบที่น่าตื่นตาตื่นใจนี้โดยypercube :

SELECT x.*
FROM (SELECT NULL AS SomeCol) AS dummy
CROSS APPLY
(
  SELECT
    ID,
    SomeCol AS MyTest
  FROM dbo.Customers
) AS x;

มันได้ผลเช่นนี้:

  • ถ้าdbo.Customersมีคอลัมน์ชื่อSomeColแล้วSomeColในSomeCol AS MyTestจะแก้เป็นdbo.Customers.SomeCol;

  • หากตารางไม่มีคอลัมน์ดังกล่าวการอ้างอิงจะยังคงใช้ได้เพราะตอนนี้มันจะได้รับการแก้ไขเป็นdummy.SomeCol: dummyคอลัมน์สามารถอ้างอิงได้ในบริบทนั้น

คุณสามารถระบุคอลัมน์ "อะไหล่" ได้หลายวิธี เคล็ดลับไม่ได้ใช้นามแฝงของตารางสำหรับคอลัมน์ดังกล่าว (ซึ่งเป็นวิธีปฏิบัติที่ขมวดคิ้วในสถานการณ์ส่วนใหญ่ แต่ในกรณีนี้การข้ามนามแฝงของตารางจะช่วยให้คุณแก้ไขปัญหาได้)

หากมีการใช้ตารางในการเข้าร่วมและตารางอื่นมีของตัวเองSomeColคุณอาจจะต้องใช้แบบสอบถามข้างต้นเป็นตารางที่ได้รับมาก่อนที่จะใช้ในการเข้าร่วมเพื่อให้เคล็ดลับทำงานต่อไปนี้:

SELECT ...
FROM
(
  SELECT x.*
  FROM (SELECT NULL AS SomeCol) AS dummy
  CROSS APPLY (
    SELECT
      ID,
      SomeCol AS MyTest
    FROM dbo.Customers
  ) AS x
) AS cust
INNER JOIN ...
;

1
ฉันสงสัยว่าคอมไพเลอร์ SQL นั้นซับซ้อนหรือไม่ เด็ดสุด ๆ ในสิ่งที่คุณสามารถทำได้
Max Vernon

9

วิธีหนึ่งในการทำเช่นนี้คือการตรวจสอบการมีอยู่ของคอลัมน์จากนั้นสร้าง Dynamic SQL ตามว่าคอลัมน์นั้นมีอยู่หรือไม่

หากไม่มี Dynamic SQL, SQL Server จะพยายามประเมินว่ามีคอลัมน์อยู่ก่อนหรือไม่แม้แต่จะเรียกใช้งาน Statment ทำให้เกิดข้อผิดพลาด

อย่างไรก็ตามหมายความว่าคุณจะมี 2 ข้อซักถามในการเขียนและอาจมีการเปลี่ยนแปลงในอนาคต แต่ฉันไม่เชื่อว่าคุณควรตั้งเป้าหมายSELECTงบในคอลัมน์ที่อาจไม่มีอยู่จริง

declare @SQL varchar(max)

If exists (select 1 from sys.columns where Name = N'NameOfColumn' and object_id=object_id(N'yourTableName'))
begin
set @SQL = 'select ID, NameOfColumn from yourTableName'
exec(@sql)
end
else
begin
Print 'Column does not exist'
end

อย่างไรก็ตามใช่แล้วจะต้องอยู่ในแถลงการณ์เดียว ในที่สุดฉันกำลังมองหาฟังก์ชั่นระบบเวทมนตร์ที่ไม่มีอยู่จริง
Carson Reinke

4

คุณสามารถใช้ XML เพื่อสืบค้นคอลัมน์ที่อาจอยู่ในตาราง

สร้าง XML จากคอลัมน์ทั้งหมดต่อแถวใน cross ที่ใช้และแยกค่าโดยใช้values()ฟังก์ชัน

ในรหัสแบบสอบถามนี้เป็นที่รู้จักกันเพื่อให้ได้จากตารางโดยตรง Col1 และ Col2 อาจอยู่ที่นั่นหรือไม่สามารถใช้ XML ได้

select T.ID,
       TX.X.value('(Col1/text())[1]', 'int') as Col1,
       TX.X.value('(Col2/text())[1]', 'int') as Col2
from T
  cross apply (select T.* for xml path(''), type) as TX(X)

ซอ Fiddle


-1

วิธีการของฉันแตกต่างจากคนอื่นเพียงเล็กน้อยเท่านั้น ฉันชอบที่จะใช้ระบบนี้และได้รับการนับเพราะคุณสามารถกำหนดจำนวนคอลัมน์ให้กับตัวแปรที่ด้านบนของแบบสอบถามแล้วเลือกที่จะดำเนินการต่อไปหรือไม่ขึ้นอยู่กับว่า ข้อเสียคือ ... ถ้าคุณมีชื่อคอลัมน์เดียวกันในหลายตารางคุณไม่แน่ใจว่ามีคอลัมน์อยู่ในตารางที่คุณต้องการสอบถาม อย่างไรก็ตามเทคนิคนี้ใช้งานได้กับตารางบางอย่างเช่นกันเนื่องจากคุณเพียงต้องการนับเท่านั้น

'ปัญหา' ด้วยการถามเป็นพิเศษคือ - ปัญหาที่คุณประสบ โดยทั่วไปหากค่า NULL ทำให้คุณออก ... หาวิธีอื่นในการตรวจสอบการมีอยู่ นี่เป็นวิธีหนึ่งในการทำเช่นนั้นโดยไม่ทำให้เซิร์ฟเวอร์เสีย

SELECT COUNT(*) FROM sys.columns WHERE sys.columns.name = 'FarmID'

1
ทำไมไม่ใช้sysobjectsทั้งในแบบสอบถามของคุณเพื่อตรวจสอบว่าตารางเฉพาะมีคอลัมน์ดังกล่าว?
ypercubeᵀᴹ

ใช่…ฉันพูดถึงว่าสามารถทำได้…คุณสามารถทำเช่นเดียวกันบนตารางที่คุณกำลังสอบถามเกี่ยวกับ…ฉันเพิ่งแสดงรูปแบบทั่วไปสำหรับการใช้ COUNT เพราะ COUNT ไม่ผิดพลาดเมื่อ COUNT เป็นศูนย์และ…ฉันคิดว่าฉันควร พูดถึงว่าคุณสามารถกำหนดให้ตัวแปรเช่นกัน (เช่น SELECT COUNT (*) AS myVarName …)
jinzai

1
ฉันไม่เห็นว่าสิ่งนี้จะดีกว่าการสืบค้นของ Mark อย่างไร SELECT 1 ...ไม่ผิดพลาดอย่างใดอย่างหนึ่ง
ypercubeᵀᴹ

ฉันไม่ได้บอกว่ามันดีกว่า แต่ก็เป็นวิธีที่ง่ายกว่ามากในการบรรลุผลลัพธ์เดียวกัน SELECT 1 อาจไม่ใช่ข้อผิดพลาด แต่ไม่ใช่สิ่งเดียวกันกับ COUNT SELECT ส่งคืนบางสิ่งบางอย่าง ... แม้ว่าจะเป็นค่า NULL COUNT จะต้องส่งคืนหมายเลขเดียวเท่านั้น วิธีนี้จะเร็วขึ้นและฉันไม่ได้กล่าวถึงจำนวนที่สามารถใช้ในภายหลัง
jinzai

หากคุณต้องการนับ ok แต่EXISTS (SELECT ...)มักจะเร็วกว่า(SELECT COUNT(*) ...)ไม่ใช่วิธีอื่น
ypercubeᵀᴹ

-3

ถ้าฉันเข้าใจถูกต้อง ...

คุณสามารถใช้แบบสอบถามเช่นด้านล่างและดำเนินการตามการนับ ... หากการนับคือ> 1 นั่นหมายความว่าคุณมีคอลัมน์ในตารางนั้นและ count = 0 คุณจะไม่มีคอลัมน์นั้นในนั้น โต๊ะ

จำนวนที่เลือก (*)
จาก INFORMATION_SCHEMA.COLUMNS ที่ COLUMN_NAME ใน ('Id')
และ TABLE_SCHEMA = 'dbo' และ TABLE_NAME = 'UserBase';


4
ไม่คุณไม่เข้าใจอย่างถูกต้อง ตรวจสอบกรณีที่เกิดขึ้นกับ INFORMATION_SCHEMA มุมมองจาก @AaronBertrand
Kin Shah
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.