4

我有一个客户给我的一个奇怪的问题。

他有一个数据列表,括号之间的日期如下:

Foo (14/08/2012)
Bar (15/08/2012)
Bar (16/09/2012)
Xyz (20/10/2012)

但是,他希望列表显示如下:

Foo (14/08/2012)
Bar (16/09/2012)
Bar (15/08/2012)
Foot (20/10/2012)

(请注意,第二个 Bar 已上移一位)

因此,其背后的逻辑是,列表必须按日期升序排序,除非两行具有相同的名称('Bar')。如果它们具有相同的名称,则必须以 LATEST 日期在顶部进行排序,同时保持其他排序顺序。

这甚至有可能吗?我尝试了很多ORDER BY子句,但找不到合适的子句。有人有想法吗?

我应该指定此数据来自 sql server 数据库中的表(名称和日期位于两个不同的列中)。所以我正在寻找一个可以进行我想要的排序的 SQL 查询。

(我已经把这个例子简化了很多,所以如果你需要更多的上下文,不要犹豫,问)

4

5 回答 5

4

这行得通,我想

declare @t table (data varchar(50), date datetime)

insert @t 
values
('Foo','2012-08-14'),
('Bar','2012-08-15'),
('Bar','2012-09-16'), 
('Xyz','2012-10-20')

select t.*
from @t t
    inner join (select data, COUNT(*) cg, MAX(date) as mg from @t group by data) tc
        on t.data = tc.data
order by case when cg>1 then mg else date end, date desc

生产

data       date
---------- -----------------------
Foo        2012-08-14 00:00:00.000
Bar        2012-09-16 00:00:00.000
Bar        2012-08-15 00:00:00.000
Xyz        2012-10-20 00:00:00.000
于 2012-08-14T14:58:16.717 回答
2

比任何其他发布的答案都具有更好性能的方法是完全使用 aORDER BY而不是 aJOIN或 using CTE

DECLARE @t TABLE (myData varchar(50), myDate datetime)

INSERT INTO @t VALUES 
('Foo','2012-08-14'),
('Bar','2012-08-15'),
('Bar','2012-09-16'), 
('Xyz','2012-10-20')

SELECT *
FROM @t t1
ORDER BY (SELECT MIN(t2.myDate) FROM @t t2 WHERE t2.myData = t1.myData), T1.myDate DESC

这完全符合您的要求,并且可以与任何索引一起使用,并且比任何其他答案都更好地处理大量数据。

此外,更清楚您在这里实际尝试做什么,而不是用连接的复杂性掩盖真实逻辑并检查连接项目的数量。

于 2012-08-15T06:48:27.647 回答
1

这个使用分析函数来执行排序,它只需要从你的表中选择一个。

内部查询查找名称更改的间隙。这些间隙用于识别下一个查询中的组,外部查询按这些组进行最终排序。

我在这里(SQL Fiddle)用扩展的测试数据尝试过。

SELECT name, dat
FROM (
  SELECT name, dat, SUM(gap) over(ORDER BY dat, name) AS grp
  FROM (
    SELECT name, dat,
          CASE WHEN LAG(name) OVER (ORDER BY dat, name) = name THEN 0 ELSE 1 END AS gap
    FROM t
  ) x
) y
ORDER BY grp, dat DESC

扩展测试数据

('Bar','2012-08-12'),
('Bar','2012-08-11'),
('Foo','2012-08-14'),
('Bar','2012-08-15'),
('Bar','2012-08-16'),
('Bar','2012-09-17'),
('Xyz','2012-10-20')

结果

Bar     2012-08-12
Bar     2012-08-11
Foo     2012-08-14
Bar     2012-09-17
Bar     2012-08-16
Bar     2012-08-15
Xyz     2012-10-20
于 2012-08-16T06:14:38.203 回答
0

我认为这是可行的,包括我在评论中询问的情况:

declare @t table (data varchar(50), [date] datetime)

insert @t 
values
('Foo','20120814'),
('Bar','20120815'),
('Bar','20120916'), 
('Xyz','20121020')

; With OuterSort as (
    select *,ROW_NUMBER() OVER (ORDER BY [date] asc) as rn from @t
)
--Now we need to find contiguous ranges of the same data value, and the min and max row number for such a range
, Islands as (
    select data,rn as rnMin,rn as rnMax from OuterSort os where not exists (select * from OuterSort os2 where os2.data = os.data and os2.rn = os.rn - 1)
    union all
    select i.data,rnMin,os.rn
    from
        Islands i
            inner join
        OuterSort os
            on
                i.data = os.data and
                i.rnMax = os.rn-1
), FullIslands as (
    select
        data,rnMin,MAX(rnMax) as rnMax
    from Islands
    group by data,rnMin
)
select
    *
from
    OuterSort os
        inner join
    FullIslands fi
        on
            os.rn between fi.rnMin and fi.rnMax
order by
    fi.rnMin asc,os.rn desc

它首先计算OuterSortCTE 中的初始排序。然后,使用两个 CTE (IslandsFullIslands),我们计算该排序中相同数据值出现在相邻行中的部分。完成后,我们可以通过所有相邻值将具有的任何值(例如它们所属的“岛”的最低行号)计算最终排序,然后在“岛”内,我们使用相反的最初计算的排序顺序。

但是请注意,这对于大型数据集可能不太有效。在示例数据中,它显示需要对基表进行 4 次表扫描,以及一个假脱机。

于 2012-08-15T06:35:14.057 回答
-2

尝试类似...

ORDER BY CASE date
    WHEN '14/08/2012' THEN 1
    WHEN '16/09/2012' THEN 2
    WHEN '15/08/2012' THEN 3
    WHEN '20/10/2012' THEN 4
END

在 MySQL 中,您可以执行以下操作:

ORDER BY FIELD(date, '14/08/2012', '16/09/2012', '15/08/2012', '20/10/2012')

在 Postgres 中,您可以创建一个函数 FIELD 并执行以下操作:

CREATE OR REPLACE FUNCTION field(anyelement, anyarray) RETURNS numeric AS $$
  SELECT
    COALESCE((SELECT i
              FROM generate_series(1, array_upper($2, 1)) gs(i)
              WHERE $2[i] = $1),
             0);
$$ LANGUAGE SQL STABLE

如果不想使用 CASE,可以尝试在 SQL Server 中找到 FIELD 函数的实现。

于 2012-08-14T14:59:51.240 回答