2017-09-20 1 views
1

문자열을 일부 구분 기호로 분리하고 테이블에 이러한 값을 반환하는 작은 sql 함수를 사용합니다.ORDER BY (SELECT NULL)

ALTER FUNCTION [shark].[SplitStrings] 
(
    @List  VARCHAR(MAX), 
    @Delimiter VARCHAR(255) 
) 
RETURNS TABLE 
AS 
    RETURN (SELECT [Item], ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS [Id] FROM 
     (SELECT Item = x.i.value('(./text())[1]', 'varchar(max)') 
     FROM (SELECT [XML] = CONVERT(XML, '<i>' 
     + REPLACE(@List, @Delimiter, '</i><i>') + '</i>').query('.') 
     ) AS a CROSS APPLY [XML].nodes('i') AS x(i)) AS y 
     WHERE Item IS NOT NULL 
); 

문제는 이것이 문자열의 요소 순서를 변경할 수 있는지 여부입니다.

Ex.

SELECT * FROM [shark].[SplitStrings] ('1,2,3,4,5', ',') 

수있는이

1 
5 
3 
4 
2 

대신

1 
2 
3 
4 
5 

의 복귀?

추가 정보 : 몇 달 동안 정상적으로 작업 한 후에 구성 요소 중 하나에서 버그를 발견했으며이 버그가 발생할 수있는 유일한 원인은 언급 된 절차입니다. 어떤 식 으로든 65000 개의 요소가 포함 된 문자열 배열의 순서가 변경되었습니다 (구분 기호가있는 문자열의 총 길이는 65000 * 11). 동일한 SQL Server에서 동일한 오류를 재현하려고했지만 행운을 보지 않았습니다. 귀하의 의견과 답변은이 sproc을 유죄로 만들었습니다.

+3

'ORDER BY' 절이있는 것은 모든 행에'ROW_NUMBER() '값을 할당하는 것을 정의하는 것입니다. 그러나 모든 행에 해당 절에서 동일한 값이 지정되므로 할당 된 행 번호는 절대 보장되지 않습니다. 그리고 결과가 반환되는 순서에 영향을주는 보장은 없습니다 *. –

+1

@Damien_The_Unbeliever에 동의합니다. 논리적 순서가 없으면 순서가 잘못 될 수 있습니다.몇 년 동안 데이터를 원하는 순서로 반환 한 쿼리가 있었고 SQL Server 업그레이드 후에는 명시 적 순서가 없기 때문에 다른 순서로 데이터를 제공하기 시작했습니다. 정확한 행 번호 매기기를 제공하기 위해 유사한 루프 인 함수를 만들었습니다. 효율적이지는 않지만 정확합니다. – UnhandledExcepSean

+2

XQuery *는 요소를 순서대로 처리하므로이 기능을보다 강력하게 만들고 싶다면 거기에 카운터를 구현하십시오 (XQuery에는 기본 노드 계산 기능이 있지만 SQL Server에서는이를 구현하지 않습니다). XML 노드에는 순서가 있습니다. 'ROW_NUMBER()'는 그렇지 않습니다. 실제로, 최적화 프로그램이 순조롭게 진행되는 것을 관찰 할 수 있는지 여부는 모르겠다. 가능하다면, 큰 세트 일 수도 있고, 병렬 계획이 선택되었지만 문자열이 너무 작아서 트리거하지 못할 수도있다. 그. –

답변

1

일반적으로 select 문은 항상 정렬되지 않은 결과 집합을 반환합니다. 따라서 일반적인 질문에 대한 대답은 다음과 같습니다. 예, select 문은 요소의 순서를 반환 할 수 있습니다. 이것은 SQL 표준을 확인합니다. (그리고 다른 어떤 것도 신뢰하지 않는 것이 좋습니다.)

하지만 : 함수 내에서 암시 적 순서를 지정합니다. 이 순서는 XML-Fragment 내의 -elements 순서로 생성됩니다. 이 XML은 XML로 변환 된 문자열을 구성한 순서대로 처리됩니다. 이것은 교차 적용의 오른쪽으로 사용됩니다 (사용할 수 없으며 여기까지 순서가 필요하지 않습니다). 그래서 귀하의 질문에 대한 대답은 : 아니오, 귀하의 선택 진술은 항상 주어진 요소의 순서를 반환합니다. 코멘트에 맞지 않는

+2

XML은 요소 순서대로 처리되지만 데이터를 순서대로 반환한다는 내용은 읽지 않았습니다. 데이터의 순서가 명시 적 순서보다 중요하면 이동하는 유일한 안전한 방법입니다. https://blogs.msdn.microsoft.com/conor_cunningham_msft/2008/08/27/no-seatbelt-expecting-order-without-order-by/ –

+2

Sean이 지정한 이유 때문에 정확하지 않습니다. 특히 'CROSS APPLY'는 주문이 없음을 의미합니다. * T-SQL의 Nothing *은 'ORDER BY'를 제외한 순서를 의미하지만, 여기에서 사용 된 'ORDER BY (SELECT NULL)'이 아니라는 것은 분명히 비 결정적입니다. 명령문이 'ORDER BY Id'로 다시 래핑 된 경우에도 내부 행 집합이 비 결정적 순서를 가지므로 (궁극적으로 결정 론적 순서를 줄 수는 없습니다) 궁극적으로 아무것도 보장하지 않습니다. * 연습 *에서, 이와 같은 질의는 거의 확실하게 순서대로 행 처리를 할 것이지만 * 보증은 없습니다. –

+0

@Jeroen : 명시 적 '주문자'가없는 한 특정 주문에 대해 SQL에 대한 보장이 없다는 데 모두 동의한다고 생각합니다. 주어진 SQL에는 XML 요소 내에 순서가 있습니다. XML 요소에는 정의에 의한 순서가 있습니다 (XML 속성과는 달리). 따라서이 XML 요소를 처리하는 것은 정보를 놓치지 않는 한 해당 순서를 유지해야합니다. (구조에 따라 선언 된대로 행렬 XML 노드에서 순서를 선언 할 방법이 없습니다.) – Christian4145

1

일부 더 많은 정보 :

그 질문에 대한 최소한의 문을 볼 수있는 작품이 감소 질문

SELECT x.i.value('(./text())[1]', 'varchar(100)') as Item 
FROM 
    (SELECT CONVERT(XML, '<i>1</i><i>2</i>') as [XML]) AS a 
CROSS APPLY [XML].nodes('i') AS x(i); 

등 : 결과는이 순서에있을 수 있습니다 ?

2 
1 

이 쿼리의 실행 계획은 다음과 같습니다

|--Compute Scalar(DEFINE:([Expr1011]=[Expr1010])) 
    |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1000], XML Reader with XPath filter.[id])) 
     |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1000])) 
     | |--Constant Scan(VALUES:((CONVERT(xml,'<i>1</i><i>2</i>',0)))) 
     | |--Filter(WHERE:(STARTUP EXPR([Expr1000] IS NOT NULL))) 
     |   |--Table-valued function 
     |--Stream Aggregate(DEFINE:([Expr1010]=MIN(CASE WHEN [Expr1000] IS NULL THEN NULL ELSE CASE WHEN datalength(XML Reader with XPath filter.[value])>=(128) THEN CONVERT_IMPLICIT(varchar(100),XML Reader with XPath filter.[lvalue],0) ELSE CONVERT_IMPLICIT(varchar(100),XML Reader with XPath filter.[value],0) END END))) 
      |--Top(TOP EXPRESSION:((1))) 
        |--Compute Scalar(DEFINE:([Expr1009]=0x58)) 
         |--Filter(WHERE:(XML Reader with XPath filter.[id]=getancestor(XML Reader with XPath filter.[id],(1)))) 
          |--Table-valued function 

어쩌면 거기에 XML 리더에서 오는 데이터와 중첩 루프 내의 요소의 순서에 대한 이유는, 그러나 이것은 아니다 물론 이것에 대한 문서는 찾을 수 없습니다.

또한 XML 구조를 변경하지 않고 순서를 올바르게 유지하는 방법 (즉, XML 내에서 정렬 키 추가)에 대한 설명서가 없습니다.