T-SQL联合(不同,不是全部)和按优先级排序

时间:2018-12-20 20:46:41

标签: sql sql-server tsql sql-order-by union

假设我有一个包含3个值的Tag表(Id intName nvarchar(100)):

1 Software
2 Hardware
3 Warehouse

现在,我想用关键字查询,并将以关键字开头的关键字优先于包含关键字的关键字。所以起初我写这个查询:

SELECT 0 AS SortCol, * 
FROM Tag T
WHERE CHARINDEX(@keyword, T.Name) = 1
UNION
SELECT 1 AS SortCol, * 
FROM Tag T
WHERE T.Name LIKE ('%' + @keyword + '%')
ORDER BY SortCol, Name;

但是,由于SortCol列不再使它们区别(Warehouse值出现两次,因为两者均正确),因此无法正常工作。

enter image description here

那是我认为我需要通过摆脱该列来手动调用DISTINCT的原因:

SELECT DISTINCT T2.Id, T2.Name
FROM
    (SELECT 0 AS SortCol, * 
     FROM Tag T
     WHERE CHARINDEX(@keyword, T.Name) = 1
     UNION
     SELECT 1 AS SortCol, * 
     FROM Tag T
     WHERE T.Name LIKE ('%' + @keyword + '%')
     ORDER BY SortCol, T.Name) AS T2;

但是,这不起作用,因为出现此错误:

  

除非还指定了TOP,OFFSET或FOR XML,否则ORDER BY子句在视图,内联函数,派生表,子查询和公用表表达式中无效。

我在这里想念什么?如何在两个语句中将UNIONORDER BY一起使用?

3 个答案:

答案 0 :(得分:5)

您不需要可以使用的UNION

SELECT *
FROM   Tag T
WHERE  T.Name LIKE '%' + @keyword + '%'
ORDER  BY CASE WHEN T.Name LIKE @keyword + '%' THEN 0 ELSE 1 END,
          Name; 

答案 1 :(得分:1)

如果出于某些原因您需要此SortCol列,则可以:

DECLARE @keyword NVARCHAR(MAX) = N'ware';

WITH cte AS (
  SELECT *, ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name) rn
  FROM (
    SELECT 0 AS SortCol, * 
    FROM Tag T
    WHERE CHARINDEX(@keyword, T.Name) = 1
    UNION
    SELECT 1 AS SortCol, * 
    FROM Tag T
    WHERE T.Name LIKE ('%' + @keyword + '%')) s
)
SELECT SortCol, Id, name
FROM cte
WHERE rn = 1
ORDER BY SortCol, Name;

db<>fiddle demo

答案 2 :(得分:0)

只需将一个CASE直接放在ORDER BY子句中,例如:

If i = 0 Then 'No worksheet with the year selected by DTPicker
    With Sheets("Template")
        .Copy After:=Sheets(Sheets.Count) 'Add worksheet
        i = 1
        ActiveSheet.Name = WsName & "_" & i
    End With
ElseIf
    For counter = 1 To i Step 1
        Worksheets(WsName & "_" & counter).Activate
        If IsEmpty(Range("A1048576").value) = True Then
        Exit For
        End If
    Next counter
Else
    With Sheets("Template")
        .Copy After:=Sheets(Sheets.Count) 'Add worksheet
        ActiveSheet.Name = WsName & "_" & i
    End With
End If