【问题标题】:How do I convert MySQL that uses group by and order by clauses to T-SQL query?如何将使用 group by 和 order by 子句的 MySQL 转换为 T-SQL 查询?
【发布时间】:2012-05-02 09:08:44
【问题描述】:

我想要翻译以下 MySQL 查询,以便它在 MSSQL 中工作:

SELECT  *
FROM 
(
    SELECT      *
    FROM        ranking
    ORDER BY    rank_no ASC
            ,   effective_dt DESC
) AS sorted_rank
WHERE       sorted_rank.rank_id = 1950
GROUP BY    sorted_rank.rank_no
LIMIT 10

我花了一个下午的时间摆弄,但我一直遇到 GROUP BY 和聚合的问题以及各种其他错误。

要在作品中添加更多扳手,排名表没有主键,我认为可能需要它来让这个工作......

服务器版本Microsoft SQL Server 2000 - 8.00.2039

架构

rank_id         int(11)
week_id         int(11)
rider_id        int(11)
year_no         int(11)
rank_no         int(11)
effective_dt    datetime
lastupdate_dt   datetime
point_no        float
average_no      float  
result_qy       int(11)

数据集

INSERT INTO `ranking` (`id`, `rank_id`, `week_id`, `rider_id`, `year_no`, `rank_no`,  `effective_dt`, `lastupdate_dt`, `point_no`, `average_no`,  `result_qy`)
VALUES
(244, 1950, 417, 72253, 2007, 1, '2006-09-03 00:00:00', '2006-09-01 01:45:00', 2559.19, 426.53, 5),
(108, 1950, 426, 72253, 2007, 1, '2006-11-05 00:00:00', '2006-11-01 05:59:00', 2559.19, 426.53, 5),
(340, 1950, 386, 21767, 2006, 1, '2006-01-29 00:00:00', '2006-11-29 13:31:00', 3256.25, 814.06, 4),
(178, 1950, 420, 60369, 2007, 2, '2006-09-24 00:00:00', '2006-09-26 06:31:00', 2315.86, 385.98, 4),
(166, 1950, 417, 60369, 2007, 2, '2006-09-03 00:00:00', '2006-09-01 01:45:00', 2315.86, 385.98, 4),
(109, 1950, 426, 60369, 2007, 2, '2006-11-05 00:00:00', '2006-11-01 05:59:00', 2315.86, 385.98, 4),
(110, 1950, 426, 49428, 2007, 3, '2006-11-05 00:00:00', '2006-11-01 05:59:00', 2191.19, 365.2, 4),
(227, 1950, 417, 49428, 2007, 3, '2006-09-03 00:00:00', '2006-09-01 01:45:00', 2191.19, 365.2, 4),
(409, 1950, 388, 19570, 2006, 3, '2006-02-12 00:00:00', '2006-11-29 13:31:00', 3106.26, 776.57, 4),
(72, 1950, 399, 47036, 2006, 4, '2006-04-30 00:00:00', '2006-11-29 13:33:00', 1038.02, 346.01, 3),
(413, 1950, 388, 55533, 2006, 4, '2006-02-12 00:00:00', '2006-11-29 13:31:00', 2835.3, 708.83, 4),
(111, 1950, 426, 64517, 2007, 4, '2006-11-05 00:00:00', '2006-11-01 05:59:00', 2001.68, 333.61, 4),
(112, 1950, 426, 72379, 2007, 5, '2006-11-05 00:00:00', '2006-11-01 05:59:00', 1677.32, 279.55, 6),
(263, 1950, 420, 27123, 2007, 5, '2006-09-24 00:00:00', '2006-09-26 06:31:00', 1607.31, 267.88, 4),
(415, 1950, 388, 45738, 2006, 5, '2006-02-12 00:00:00', '2006-11-29 13:31:00', 2744.03, 686.01, 4),
(113, 1950, 426, 27123, 2007, 6, '2006-11-05 00:00:00', '2006-11-01 05:59:00', 1607.31, 267.88, 4),
(575, 1950, 420, 50354, 2007, 6, '2006-09-24 00:00:00', '2006-09-26 06:31:00', 1148.84, 191.47, 2),
(422, 1950, 388, 39070, 2006, 6, '2006-02-12 00:00:00', '2006-11-29 13:31:00', 2626.51, 656.63, 4),
(114, 1950, 426, 65745, 2007, 7, '2006-11-05 00:00:00', '2006-11-01 05:59:00', 1576.83, 262.8, 4),
(293, 1950, 388, 42127, 2006, 7, '2006-02-12 00:00:00', '2006-11-29 13:31:00', 2614.46, 653.62, 4),
(576, 1950, 420, 32669, 2007, 7, '2006-09-24 00:00:00', '2006-09-26 06:31:00', 1133.15, 188.86, 2),
(577, 1950, 420, 23242, 2007, 8, '2006-09-24 00:00:00', '2006-09-26 06:31:00', 1107.79, 184.63, 2),
(199, 1950, 420, 60322, 2007, 8, '2006-09-24 00:00:00', '2006-09-26 06:31:00', 1390.22, 231.7, 3),
(115, 1950, 426, 54984, 2007, 8, '2006-11-05 00:00:00', '2006-11-01 05:59:00', 1532.8, 255.47, 3),
(578, 1950, 420, 41116, 2007, 9, '2006-09-24 00:00:00', '2006-09-26 06:31:00', 1096.64, 182.77, 2),
(116, 1950, 426, 72386, 2007, 9, '2006-11-05 00:00:00', '2006-11-01 05:59:00', 1442.49, 240.41, 6),
(74, 1950, 399, 32669, 2006, 9, '2006-04-30 00:00:00', '2006-11-29 13:33:00', 817.64, 272.55, 3),
(818890, 1950, 1167, 77510, 0, 10, '2012-01-13 00:00:00', '2012-01-13 11:11:00', 1464.43, 366.11, 4),
(825706, 1950, 1168, 70324, 0, 10, '2012-01-20 00:00:00', '2012-01-20 11:05:00', 1259.38, 314.85, 2),
(826752, 1950, 1170, 75911, 0, 10, '2012-02-01 00:00:00', '2012-02-01 12:58:00', 1237.95, 309.49, 3);

正确的输出

1950    426     72253   2007    1   2006-11-05 00:00:00  2006-11-01 05:59:00     2559.19    426.53      5
1950    426     60369   2007    2   2006-11-05 00:00:00  2006-11-01 05:59:00     2315.86    385.98      4
1950    426     49428   2007    3   2006-11-05 00:00:00  2006-11-01 05:59:00     2191.19    365.2       4
1950    426     64517   2007    4   2006-11-05 00:00:00  2006-11-01 05:59:00     2001.68    333.61      4
1950    426     72379   2007    5   2006-11-05 00:00:00  2006-11-01 05:59:00     1677.32    279.55      6
1950    426     27123   2007    6   2006-11-05 00:00:00  2006-11-01 05:59:00     1607.31    267.88      4
1950    426     65745   2007    7   2006-11-05 00:00:00  2006-11-01 05:59:00     1576.83    262.8       4
1950    426     54984   2007    8   2006-11-05 00:00:00  2006-11-01 05:59:00     1532.8     255.47      3
1950    426     72386   2007    9   2006-11-05 00:00:00  2006-11-01 05:59:00     1442.49    240.41      6
1950    1170    75911   0       10  2012-02-01 00:00:00  2012-02-01 12:58:00     1237.95    309.49      3

【问题讨论】:

  • 你为什么按rank_no分组?您想获得ranking 的某个字段的总和以及相同的rank_no 吗?请提供ranking 表结构。
  • rank_no 的值为 1,2,3,4 等,但每个数字可以出现多次(1,1,1,1,1,2,2,2,2,2 ,3,3,3,3,3,3,4,4,4,4 等)我想要每个可能的 rank_no 的最新行,因此 GROUP BY
  • ranking 表有哪些列?
  • @Andy 听起来这是一个更大的问题。没有主键的表可能不是一个很好的设计。您能否发布表格定义。还要摆脱 MSSQL 不支持的 LIMIT 。你需要做一个TOP 10。你如何确定最新的rank_no? group by 没有识别最新的 rank_no 它只是通过将项目 1,1,1 分组为 1 来删除重复项。
  • 我认为查询中显示了相关的,但我已将架构添加到原始帖子中。

标签: mysql group-by sql-server-2000 sql-order-by


【解决方案1】:

SQL Server 2000 及更高版本

根据您的要求,您需要在每个等级中找到最近的生效日期。为此,您需要编写一个子查询,该查询将获取给定排名的最大有效日期,然后将其与行中的日期进行比较以过滤到所需的结果。这适用于 SQL Server 2000 及更高版本的所有版本。

以下查询已在 SQL Server 2000 中测试。

Click here to view the demo in SQL Fiddle

脚本

SELECT  
TOP 10  id
    ,   rank_id
    ,   week_id
    ,   rider_id 
    ,   year_no
    ,   rank_no
    ,   effective_dt 
    ,   lastupdate_dt 
    ,   point_no  
    ,   average_no 
    ,   result_qy
FROM    ranking r_outer
WHERE   rank_id = 1950
AND     effective_dt = 
        (
            SELECT  MAX(effective_dt)
            FROM    ranking r_inner
            WHERE   r_inner.rank_no = r_outer.rank_no
            AND     r_inner.rank_id = 1950
        )
ORDER BY rank_no;

SQL Server 2005 及以上版本

您需要使用 RANK 函数将结果按rank_no 列分区,并按rank_no 后跟effective_dt 的降序对每个分区进行排序。每个排序的分区部分都将被分配一个等级值,例如 1、2、3 等。您只对这些分区组中的第一个等级感兴趣。因此,外部 SELECT 将通过 rank_num = 1 过滤结果。

RANK 函数仅在SQL Server 2005 及更高版本中受支持。

Click here to view demo in SQL Fiddle using SQL Server 2012.

脚本:

SELECT
TOP 10      id 
        ,   rank_id
        ,   week_id
        ,   rider_id 
        ,   year_no
        ,   rank_no
        ,   effective_dt 
        ,   lastupdate_dt 
        ,   point_no  
        ,   average_no 
        ,   result_qy
FROM
(
    SELECT  id 
        ,   rank_id
        ,   week_id
        ,   rider_id 
        ,   year_no
        ,   rank_no
        ,   effective_dt 
        ,   lastupdate_dt 
        ,   point_no  
        ,   average_no 
        ,   result_qy
        ,   RANK() OVER(
                    PARTITION BY rank_no 
                    ORDER BY rank_no, effective_dt DESC) rownum
    FROM    ranking r
    WHERE   r.rank_id = 1950
) t1 
WHERE rownum = 1;

【讨论】:

  • 我似乎没有 RANK(),这意味着我不在 SQL Server 2005 上(我意识到我应该提到这一点)除此之外,这个解决方案看起来正是我需要的!有没有办法解决我缺乏 RANK() 的问题?
  • 请选择@@version。我们所有的解决方案都不适用于 SQL 2000 及更低版本。
  • @Namphibian - Microsoft SQL Server 2000 - 8.00.2039 再次,非常抱歉最初没有发布该信息!
  • @Siva 你打败了我,我使用了简单的行号,但是这是一种方法。很高兴看到人们使用 SQL 排名函数。
  • @Andy 你需要认真考虑升级。 SQL2000 不再受支持,而且由于不再维护,因此极易受到攻击。 SQL 2000 中的查询也会很痛苦。
【解决方案2】:

我建议在WHERE 子句中使用子查询来获取最大effective_dt 的记录(假设值在一个rank_no 内是唯一的,我猜它是一个日期时间):

SELECT TOP 10 *
FROM ranking R
WHERE R.rank_id = 1950 AND 
    R.effective_dt = (SELECT MAX(effective_dt) from ranking R2 WHERE R2.rank_no = R.rank_no AND R2.rank_id = R.rank_id)
ORDER BY R.rank_no

【讨论】:

  • 好的,这行不通,但我意识到你是在黑暗中射击 - 我已经用示例数据集和预期的输出更新了这个问题。感谢您到目前为止的时间!
【解决方案3】:

请注意,如果没有主键或在此表上聚集,当数据增长时,它会非常缓慢。我会认真建议您找出哪些字段应该是键。没有聚集索引的表是一个堆,它们没有顺序(通常按照插入的顺序存储)。

您也可以尝试以下查询。

/*
    This CTE will sort the table into a usable structure. To see what it does run the select statement seperately.
*/
;WITH CTERankID
AS
(

SELECT  *
        ,ROW_NUMBER() OVER(PARTITION BY rank_no ORDER BY effective_Dt DESC) AS RowNo        
FROM ranking

)
SELECT  TOP 10   
    rank_id
    ,week_id
    ,year_no
   ,rank_no
   ,effective_dt
   ,lastupdate_dt
   ,point_no
   ,average_no
   ,result_qy
   ,rowno
FROM CTERankID AS rankTable
WHERE rankTable.RowNo=1
AND rankTable.rank_id = 1950

希望它会有所帮助。 PS 这在 MySQL 中不起作用,因为 MySQL 不支持 CTE。

【讨论】:

  • 与我对@Siva 的回复一样,我似乎没有 ROW_NUMBER() 这意味着我无法使用此解决方案。我不知道 SQL Server 版本会是一个问题,或者我会在我最初的问题中提到,我为浪费你的时间而感到难过:(
猜你喜欢
  • 1970-01-01
  • 2019-01-21
  • 1970-01-01
  • 2021-11-17
  • 2021-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多