CASE 문을 사용하여 열이 존재하고 SELECT 열이 아닌지 확인할 수없는 이유는 무엇입니까?


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

4
@Brilliand sys.columns는 훨씬 더 나은 IMHO입니다.
Aaron Bertrand

답변:


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, 다음 SomeColSomeCol 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

이를 수행하는 한 가지 방법은 열이 있는지 확인한 다음 해당 열이 존재하는지 여부에 따라 동적 SQL을 빌드하는 것입니다.

동적 SQL이 없으면 SQL Server는 명령문을 실행하기 전에 열이 존재하는지 여부를 평가하려고 시도하므로 오류가 발생합니다.

그러나 이는 나중에 작성하고 잠재적으로 변경할 두 개의 쿼리가 있음을 의미합니다. 그러나 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을 작성하고 values()함수를 사용하여 값을 추출하십시오 .

이 쿼리에서 ID는 알려져 있으므로 테이블에서 직접 가져 오십시오. 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)

SQL 바이올린


-1

내 접근 방식은 다른 방식과 약간 다릅니다. 나는 이것을 위해 시스템을 사용하고 쿼리의 상단에있는 변수에 열 수를 할당 한 다음 그에 따라 진행할지 여부를 선택할 수 있기 때문에 단순히 개수를 얻는 것을 선호합니다. 단점은… 여러 테이블에 동일한 열 이름이 있으면 쿼리하려는 테이블에 열이 있는지 확실하지 않습니다. 그러나이 기술은 특정 테이블에서만 작동합니다. 카운트 만 얻으려고하기 때문입니다.

구체적으로 요구하는 '고장'은 당신이 겪고있는 문제입니다. 일반적으로 NULL 값으로 인해 문제가 발생하면 다른 방법으로 존재 여부를 확인하십시오. 이것은 서버를 화나게 할 위험없이 그렇게하는 한 가지 방법입니다.

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

1
sysobjects특정 테이블에 이러한 열이 있는지 확인하기 위해 쿼리에서를 사용하지 않는 이유는 무엇 입니까?
ypercubeᵀᴹ

그렇습니다. 나는 할 수 있다고 언급했습니다 ... 당신이 쿼리하는 특정 테이블에서 동일한 작업을 수행 할 수도 있습니다 ... COUNT가 ZERO 일 때 COUNT가 오류가 발생하지 않기 때문에 COUNT를 사용하는 일반적인 형식을 보여주었습니다 ... 변수에 할당 할 수 있다고 언급하십시오. (예 : SELECT COUNT (*) AS myVarName…)
jinzai

1
이것이 Mark의 쿼리보다 나은지 알 수 없습니다. SELECT 1 ...오류도 없습니다.
ypercubeᵀᴹ

나는 그것이 더 낫다고 말하지는 않았지만 같은 결과를 얻는 훨씬 간단한 방법입니다. SELECT 1은 오류가 아니지만 COUNT와 동일하지 않습니다. SELECT는 SOMETHING…을 반환합니다 (NULL이더라도). COUNT는 하나의 숫자 만 반환하면됩니다. 이 방법은 더 빠르며 나중에 카운트를 사용할 수 있다고 언급했습니다.
jinzai 2016 년

카운트가 필요한 경우 괜찮습니다. 그러나 EXISTS (SELECT ...)일반적으로 (SELECT COUNT(*) ...)다른 방법이 아닌 보다 빠릅니다 .
ypercubeᵀᴹ

-3

내가 제대로 이해했다면 ...

아래와 같은 쿼리를 사용하고 카운트에 따라 적절하게 작동 할 수 있습니다 ... 카운트가 1보다 크면 해당 테이블에 col이 있고 count = 0이면 해당 col이 없습니다. 표


COLUMN_NAME IN ( 'Id')
및 TABLE_SCHEMA = 'dbo'및 TABLE_NAME = 'UserBase'; INFORMATION_SCHEMA.COLUMNS에서 SELECT count (*) ;


4
아니, 당신은 올바르게 이해하지 못했습니다. @AaronBertrand의 INFORMATION_SCHEMA 조회수에 대한 사례 도 확인하십시오 .
Kin Shah
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.