合并两个具有不同 ORDER BY 的 SELECT 查询

Merge two SELECT queries with different ORDER BY

我有一个故事 table,我需要以下查询: - 前 6 行按距离排序(我计算的) - 下一行按 TIME 属性 降序

排序
declare @profileID int
set @profileID = 6

declare @longitude float
set @longitude = 17.6009169090776

declare @latitude float
set @latitude = 46.9548404806283

SELECT
        first.*
        FROM
            (
                SELECT top 6
                    [dbo].[Story].*,
                    SQRT( POWER(@Longitude - [dbo].[Story].[Longitude], 2) + POWER(@Latitude - [dbo].[Story].[Latitude], 2)) as [DistanceFromUser]
                FROM
                    [dbo].[Follow]
                LEFT JOIN
                    [dbo].[Story]
                    ON
                    [dbo].[Follow].[Followed] = [dbo].[Story].[ProfileID]
                WHERE
                    [dbo].[Follow].[Follower] = @ProfileID and
                    [dbo].[Story].IsDraft = 0
                ORDER BY 
                    [DistanceFromUser] asc
            ) first

        UNION ALL

        SELECT
            last.*
        FROM
            (
                SELECT TOP 100 PERCENT
                    [dbo].[Story].*,
                    SQRT( POWER(@Longitude - [dbo].[Story].[Longitude], 2) + POWER(@Latitude - [dbo].[Story].[Latitude], 2)) as [DistanceFromUser]
                FROM
                    [dbo].[Follow]
                LEFT JOIN
                    [dbo].[Story]
                    ON
                    [dbo].[Follow].[Followed] = [dbo].[Story].[ProfileID]
                WHERE
                    [dbo].[Follow].[Follower] = @ProfileID and
                    [dbo].[Story].IsDraft = 0
                **ORDER BY 
                    Time desc**
            ) last

我的问题是第二个查询。它不会按 TIME 属性 对第 6 行后的记录进行降序排序,而是按升序排序。

thnx

如果您希望结果集以特定方式排序,那么 最外层 SELECT 需要一个 ORDER BY.

您可以通过在外部 ORDER BY 中包含多个键来控制排序。如果我正确读取查询,唯一的区别是 order by,因此将查询逻辑放在 CTE 中:

WITH sf as (
       SELECT s.*,
              SQRT( POWER(@Longitude - s.[Longitude], 2) + POWER(@Latitude - s.[Latitude], 2)) as [DistanceFromUser]
        FROM [dbo].[Follow] f LEFT JOIN
             [dbo].[Story] s
             ON f.[Followed] = s.[ProfileID]
        WHERE f.[Follower] = @ProfileID and
              s.IsDraft = 0
       )
SELECT sf.*
FROM ((SELECT TOP (6) sf.*, 1 as ord
       FROM sf
       ORDER BY [DistanceFromUser] ASC
      ) UNION ALL
      (SELECT TOP (6) sf.*, 2 as ord
       FROM sf
       ORDER BY Time DESC
      ) 
     ) sf
ORDER BY ord,
         (CASE WHEN ord = 1 THEN DistanceFromUser END) ASC,
         (CASE WHEN ord = 2 THEN Time END) DESC;

您也可以使用 window 函数执行此操作:

WITH sf as (
       SELECT s.*,
              SQRT( POWER(@Longitude - s.[Longitude], 2) + POWER(@Latitude - s.[Latitude], 2)) as [DistanceFromUser]
        FROM [dbo].[Follow] f LEFT JOIN
             [dbo].[Story] s
             ON f.[Followed] = s.[ProfileID]
        WHERE f.[Follower] = @ProfileID and
              s.IsDraft = 0
       )
SELECT sf.*
FROM (SELECT sf.*, 
             ROW_NUMBER() OVER (ORDER BY DistanceFromUser) as seqnum_d,
             ROW_NUMBER() OVER (ORDER BY Time DESC) as seqnum_t
       FROM sf
      ) 
     ) sf
WHERE seqnum_d <= 6 OR seqnum_t <= 6
ORDER BY ord,
         (CASE WHEN seqnum_d <= 6 THEN DistanceFromUser END) ASC,
         (CASE WHEN seqnum_t <= 6 THEN Time END) DESC;

您的版本可能包含同一行两次。对于这两种情况,此版本不会重复前 6 行。

试试这个

SELECT
        first.*
        FROM
            (
                SELECT top 6
                    [dbo].[Story].*,
                    SQRT( POWER(@Longitude - [dbo].[Story].[Longitude], 2) + POWER(@Latitude - [dbo].[Story].[Latitude], 2)) as [DistanceFromUser]
               ,1 as ord
                FROM
                    [dbo].[Follow]
                LEFT JOIN
                    [dbo].[Story]
                    ON
                    [dbo].[Follow].[Followed] = [dbo].[Story].[ProfileID]
                WHERE
                    [dbo].[Follow].[Follower] = @ProfileID and
                    [dbo].[Story].IsDraft = 0
                ORDER BY 
                    [DistanceFromUser] asc
            ) first

        UNION ALL

        SELECT
            last.*
        FROM
            (
                SELECT TOP 100 PERCENT
                    [dbo].[Story].*,
                    SQRT( POWER(@Longitude - [dbo].[Story].[Longitude], 2) + POWER(@Latitude - [dbo].[Story].[Latitude], 2)) as [DistanceFromUser]
               ,row_number() over(order by Time desc) as ord
                FROM
                    [dbo].[Follow]
                LEFT JOIN
                    [dbo].[Story]
                    ON
                    [dbo].[Follow].[Followed] = [dbo].[Story].[ProfileID]
                WHERE
                    [dbo].[Follow].[Follower] = @ProfileID and
                    [dbo].[Story].IsDraft = 0
                **ORDER BY 
                    Time desc**
            ) last

我的尝试(例子)

declare @ta as table 
(
    id int
    ,na varchar(100)
    ,sal numeric(18,2)
)

insert into @ta( id,na,sal) values (1,'aa',10)
insert into @ta( id,na,sal) values (3,'bb',100)
insert into @ta( id,na,sal) values (2,'c',5)
insert into @ta( id,na,sal) values (4,'dd',50)

select * from
(select top 2 * , 1 as ord from @ta order by id) as f
union all
select * from (select top 100 percent * , row_number() over(order by sal desc) ord from @ta order by sal desc
) as tt

所以我以下一个解决方案结束,感谢大家

WITH TempTable as 
(
    SELECT [dbo].[Story].*,
        SQRT( POWER(@Longitude - [dbo].[Story].[Longitude], 2) + POWER(@Latitude - [dbo].[Story].[Latitude], 2)) as [DistanceFromUser]
    FROM 
        [dbo].[Follow] 
        LEFT JOIN
        [dbo].[Story]
        ON [dbo].[Follow].[Followed] = [dbo].[Story].[ProfileID]
    WHERE [dbo].[Follow].[Follower] = @ProfileID and
        [dbo].[Story].IsDraft = 0
)


SELECT
        first.*
        FROM
            (
                SELECT top 6
                    *,
                    1 as ord
                FROM
                    TempTable
                ORDER BY 
                    [DistanceFromUser] asc
            ) first

        UNION ALL

        SELECT
            last.*
        FROM
            (
                SELECT TOP 100 PERCENT
                    *,
                    row_number() over(order by Time desc) as ord
                FROM
                    TempTable
                ORDER BY 
                    Time desc
            ) last