쿼리를 작성하는 동안 쿼리를 실행할 때 SELECT를 구문 분석하기 전에 SQL Server가 쿼리에서 WHERE를 구문 분석하는 것이 어렵다는 것을 알았습니다.
MSDN 문서 등은 일반적인 논리 파싱 순서 SELECT은 (따라서 “이런 개체 [별명]”의 오차가 다른 절에서 열 별칭을 사용하려고하지 않을 때의 결과) 거의 마지막 해석되도록 것을 말한다. 도 있었다 제안 별칭 (이 동작은 ANSI 표준의 일부임을 시사) ANSI 표준 준수 문제를 인용하여 Microsoft 팀에 의해 격추 된 사용 어디서나, 할 수 있도록하는가.
프로그래머 (DBA가 아님) 로서이 동작이 다소 혼란 스럽다는 것을 알았습니다. 왜냐하면 열 별칭을 갖는 목적을 크게 상실하거나 최소한 열 별칭이 훨씬 강력하다면 실제로 별칭을 사용할 수있는 유일한 위치 는 ORDER BY에 있기 때문에 쿼리 실행에서 앞서 구문 분석되었습니다 . 프로그래머로서 쿼리를 더욱 강력하고 편리하며 건조하게 만들 수있는 기회가없는 것 같습니다.
SELECT 및 ORDER BY 이외의 열에 별칭을 사용할 수 없다고 결정하는 다른 이유가 있기 때문에 눈에 띄는 문제가있는 것처럼 보입니다. 그러나 그 이유는 무엇입니까?
답변
요약
할 수 없었던 논리적 인 이유 는 없지만, 이점은 적으며 즉시 명백하지 않을 수있는 함정이 있습니다.
연구 결과
나는 약간의 연구를하고 좋은 정보를 찾았다. 다음은 2012-08-09 17:49 GMT의 신뢰할 수있는 기본 소스 (익명으로 유지하려는)의 직접적인 인용입니다.
SQL이 처음 발명되었을 때 SELECT 절에 별칭이 없었습니다. 이것은 1986 년에 ANSI에 의해 언어가 표준화 될 때 수정 된 심각한 단점이었습니다.
이 언어는 “비 절차 적”, 즉 언어를 찾는 방법을 지정하지 않고 원하는 데이터를 설명하기위한 것입니다. 따라서 내가 아는 한 SQL 구현이 쿼리를 처리하기 전에 전체 쿼리를 구문 분석 할 수없는 이유는 없으며 어디에서나 별칭을 정의하고 사용할 수 있습니다. 예를 들어 다음 쿼리가 유효하지 않은 이유는 없습니다.
select name, salary + bonus as pay from employee where pay > 100000
이것이 합리적인 쿼리라고 생각하지만 일부 SQL 기반 시스템은 구현 관련 이유로 별칭 사용에 대한 제한을 도입 할 수 있습니다. SQL Server가이 작업을 수행한다고 들었습니다.
SQL-86 표준에 대한 추가 연구와 최신 DBMS가 별칭 재사용을 지원하지 않는 이유에 관심이 있지만 아직까지는 아직 멀지 않았습니다. 우선, 문서를 어디서 구할 수 있는지 또는 누가위원회를 정확하게 구성했는지 알아낼 수 없습니다. 누구든지 도울 수 있습니까? 또한 SQL Server의 원래 Sybase 제품에 대해 더 알고 싶습니다.
이 연구와 몇 가지 추가 생각을 통해 다른 절에서 별칭을 사용하면 다른 언어 기능에 비해 DBMS 제조업체의 우선 순위가 결코 높지 않은 것으로 의심됩니다. 쿼리 작성자가 쉽게 해결할 수있는 것은 그리 큰 장애물이 아니기 때문에 다른 발전에 노력을 기울이는 것은 최적이 아닙니다. 또한 분명히 SQL 표준의 일부가 아니기 때문에 독점적 일 것입니다 (확실히 더 기다리고 있습니다). 그러나 약간 개선되어 DBMS 간의 SQL 호환성이 손상되었습니다. 비교하면 CROSS APPLY
(실제로 외부 참조를 허용하는 파생 테이블에 지나지 않습니다.) 큰 변화이지만 독점은 다른 방식으로는 쉽게 수행 할 수없는 놀라운 표현력을 제공합니다.
어디서나 별칭을 사용할 때의 문제
SELECT 항목을 WHERE 절에 넣을 수 있으면 쿼리의 복잡성 (따라서 우수한 실행 계획을 찾는 복잡성)을 폭발적으로 확장 할 수있을뿐만 아니라 완전히 비논리적 인 것들을 생각 해낼 수 있습니다. 시험:
SELECT X + 5 Y FROM MyTable WHERE Y = X
MyTable에 이미 열 Y가있는 경우, 어느 것이 WHERE 절을 참조합니까? 해결책은 CTE 또는 파생 테이블을 사용하는 것입니다. 대부분의 경우 추가 비용이 들지 않지만 동일한 최종 결과를 얻을 수 있습니다. CTE와 파생 테이블은 별칭을 한 번만 사용할 수 있도록하여 모호성을 해결합니다.
또한 FROM 절에서 별명을 사용하지 않으면 의미가 있습니다. 당신은 이것을 할 수 없습니다 :
SELECT
T3.ID + (SELECT Min(Interval) FROM Intervals WHERE IntName = 'T') CalcID
FROM
Table1 T
INNER JOIN Table2 T2
ON T2.ID = CalcID
INNER JOIN Table3 T3
ON T2.ID = T3.ID
즉, (T2 비밀리 그 테이블은 가입리스트에 제시되기 전에, T3의 값을 참조하고있는 점에서), 원형의 기준 터무니 보이지. 이건 어때:
INSERT dbo.FinalTransaction
SELECT
newid() FinalTransactionGUID,
'GUID is: ' + Convert(varchar(50), FinalTransactionGUID) TextGUID,
T.*
FROM
dbo.MyTable T
newid () 함수가 실행 계획에 두 번 배치되어 두 열이 완전히 다른 값을 표시하게 만드는 데 얼마나 걸립니까? 위의 쿼리가 CTE 또는 파생 테이블에서 N 수준 깊이 사용되는 경우는 어떻습니까? 나는 당신이 상상할 수있는 것보다 문제가 더 나쁘다는 것을 보증한다. 쿼리 계획에서 상황이 한 번만 평가되는 시점이나 시점에 대해 불일치 문제 가 이미 발생했으며 Microsoft는 이를 해결하지 않을 것이라고 말했습니다.쿼리 대수를 올바르게 표현하기 때문에 일부는 예상치 못한 결과가 나오면 쿼리를 여러 부분으로 나눕니다. 체인 참조를 허용하고 잠재적으로 매우 긴 체인을 통해 순환 참조를 감지하는 것은 상당히 까다로운 문제입니다. 병렬 처리를 도입하면 제작에 악몽이 생깁니다.
참고 : WHERE 또는 GROUP BY에서 별칭을 사용해도 newid () 또는 rand ()와 같은 함수의 문제와 차이가 없습니다.
재사용 가능한 표현식을 작성하는 SQL Server 방법
CROSS APPLY / OUTER APPLY는 SQL Server에서 쿼리의 다른 곳에서 사용할 수있는 식을 만드는 한 가지 방법입니다 (FROM 절의 초반이 아님).
SELECT
X.CalcID
FROM
Table1 T
INNER JOIN Table3 T3
ON T.ID = T3.ID
CROSS APPLY (
SELECT
T3.ID + (SELECT Min(Interval) FROM Intervals WHERE IntName = 'T') CalcID
) X
INNER JOIN Table2 T2
ON T2.ID = X.CalcID
이것은 두 가지 일을합니다.
- CROSS APPLY의 모든 표현식이 “네임 스페이스”(여기서는 X)를 가져오고 해당 네임 스페이스 내에서 고유하게합니다.
- CalcID가 X에서 나올뿐 아니라 X가 아직 소개되지 않았기 때문에 테이블 T1과 T3을 조인 할 때 X에서 어떤 것도 사용할 수없는 이유를 분명히 알 수 있습니다.
나는 실제로 CROSS APPLY를 좋아합니다. 그것은 나의 충실한 친구가되었고, 나는 그것을 항상 사용합니다. 부분 UNPIVOT (기본 구문을 사용하는 PIVOT / UNPIVOT 또는 UNPIVOT / PIVOT이 필요함)이 필요합니까? CROSS APPLY로 완료했습니다. 여러 번 재사용 할 계산 된 값이 필요하십니까? 끝난. 연결된 서버를 통한 통화에 대한 실행 순서를 엄격하게 시행해야합니까? 속도가 크게 향상되었습니다. 한 가지 유형의 행만 2 행으로 분할하거나 추가 조건이 필요합니까? 끝난.
따라서 DBMS SQL Server 2005 이상에서는 최소한 더 이상 불만을 제기 할 필요가 없습니다. CROSS APPLY는 원하는 방식으로 건조하는 방법입니다.
답변
정확한 이유는 말할 수 없지만 CTE, 하위 쿼리, 파생 테이블 등을 사용하여 반복을 피하기 위해 식을 반복하는 해결 방법이 있음을 알려드립니다.
반복되는 표현식으로 쿼리를 표시하는 경우 표현식이 한 번만 나열되도록 다시 작성하는 방법을 보여줄 수 있습니다. 그러나 이것은 쿼리 작성 / 읽기의 복잡성을 감소 시키므로 효율성에 대해서는 크게 변하지 않을 것입니다. SQL Server는 일반적으로식이 반복된다는 것을 인식하는 데 능숙하며 해당 작업을 두 번 수행하지 않습니다. 다른 방법으로는 예외가 있지만 실제로 이러한 상황을 관찰 할 때 효율성에만 관심을 가져야합니다. 나는 당신이 쓴 대부분의 반복 표현이 실제로 계획에서 단 하나의 작업으로 축소 된 것으로 생각합니다.
모든 것이 말했듯이, 나는이 질문에서 내 대답의 일부를 반복 할 것입니다.
/dba/19762/why-is-the-select-clause-listed-first
다음은 표준에 따라 쿼리를 처리하는 방법에 대한 Joe Celko의 설명입니다 ( Celko 의 뉴스 그룹 게시물에서 인용 한 훔친 aspfaq.com article).
다음은 SELECT 이론이 SQL에서 적어도 이론적으로 작동하는 방법입니다. 실제 제품은 가능한 한 최적화합니다.
FROM 절에서 시작하여 모든 조인, 공용체, 교차점 및 기타 테이블 생성자가있는 작업 테이블을 작성하십시오. AS 옵션을 사용하면이 작업 테이블에 이름을 부여한 후 나머지 포함 쿼리에 사용해야합니다.
WHERE 절로 이동하여 기준을 통과하지 않는 행을 제거하십시오. 즉, 참으로 테스트하지 않습니다 (알 수 없음 및 거짓을 거부 함). WHERE 절은 FROM 절의 작업에 적용됩니다.
선택적 GROUP BY 절로 이동하여 그룹을 작성하고 각 그룹을 단일 행으로 줄이면 원래 작업 테이블이 새 그룹화 된 테이블로 바뀝니다. 그룹화 된 테이블의 행은 그룹 특성이어야합니다. (1) 그룹화 열 (2) 그룹에 대한 통계 (예 : 집계 함수) (3) 함수 또는 (4)이 세 항목으로 구성된 표현식.
선택적 HAVING 절로 이동하여 그룹화 된 작업 테이블에 적용하십시오. GROUP BY 절이없는 경우 전체 테이블을 하나의 그룹으로 취급하십시오.
SELECT 절로 이동하여 목록에서 표현식을 구성하십시오. 이는 SELECT의 스칼라 서브 쿼리, 함수 호출 및 표현식이 다른 모든 절이 완료된 후에 수행됨을 의미합니다. AS 연산자는 SELECT 목록의 표현식에도 이름을 지정할 수 있습니다. 이 새로운 이름은 한 번에 존재하지만 WHERE 절이 실행 된 후에 나타납니다. 이러한 이유로 SELECT 목록 또는 WHERE cluase에서 사용할 수 없습니다.
중첩 된 쿼리 표현식은 C, Pascal, Algol 등과 같은 블록 구조 언어에서 예상되는 일반적인 범위 지정 규칙을 따릅니다. 즉, 가장 안쪽 쿼리는 포함 된 쿼리에서 열과 테이블을 참조 할 수 있습니다.
이는 SELECT가 GROUP BY보다 많은 열을 가질 수 없음을 의미합니다. 그러나 확실히 더 적은 열을 가질 수 있습니다.
이제 Celko는 이전 버전의 표준에 대한 주요 기여자 중 하나였습니다. 당신이 WHY?
추측을 제외하고는 그 질문에 대한 확실한 대답을 얻을 수 있을지 모르겠습니다 . 내 생각에 실제 작업을 먼저 나열하면 파서가 작업 유형을 정확히 알기가 매우 쉽습니다. 20- 테이블 조인이 SELECT
or 또는 UPDATE
or DELETE
일 수 있다고 상상해보십시오. 이 엔진의 코드는 원래 문자열 구문 분석이 비용이 많이 들었던 시절에 다시 쓰여졌다는 것을 기억하십시오.
SQL 표준 FROM
이 우선적으로 지시 된 경우 , 벤더는 독립적으로 문법을 다른 순서로 구문 분석하기로 결정했을 수 있습니다. 시간.
같은 것들에 대해서도 마찬가지입니다 CASE
. 예를 들어, 순서와 단락으로 항상 처리 되는 이전에 믿었던 신화 가 잘못된 경우와 같이이 사이트 에서 시나리오를 보았습니다CASE
. 그리고 이것은 작성된 순서대로 조인을 평가하는 SQL Server, 왼쪽에서 오른쪽으로 단락 단락WHERE
또는 CTE를 여러 번 참조하더라도 한 번 또는 특정 순서로 처리하는 것과 같은 다른 일반적인 신념으로 확장됩니다 . 쿼리가 선언적으로 작동해야한다고 명시한 방식을 정확하게 반영하지 않더라도 제품은 제품의 적합성을 자유롭게 최적화 할 수 있습니다.
답변
Entity SQL 에서는 일부 상황에서 쿼리의 다른 위치에있는 표현식의 별명을 사용할 수 있습니다.
select k1, count(t.a), sum(t.a)
from T as t
group by t.b + t.c as k1
GROUP BY
절에서 표현식을 사용하려면 절에서 표현식을 정의해야합니다 SELECT
.
분명히 가능 앨리어스로 재사용 표현 SQL 쿼리에서 이런 종류의 일부를 허용 할 수 있습니다.