"按顺序排列"在子查询中

时间:2014-04-04 18:22:40

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

我正在尝试选择每个年级(9-12岁)有最多善良时间的学生。我编写了这段代码(在sql server 2012中),让学生获得最多时间:

(select top 1  stu_first, stu_last, sum(KIND_hours) as total from STUDENT inner join KIND
on student.stu_id=KIND.stu_id
where (12-(STU_CLASS_OF-2014))=9
group by stu_first, stu_last
order by total desc)

此代码有效,但是当我尝试将代码合并为两个等级时,我收到此错误:关键字' order'附近的语法不正确。 我的代码在这里

(select top 1  stu_first, stu_last, sum(KIND_hours) as total from STUDENT inner join KIND
on student.stu_id=KIND.stu_id
where (12-(STU_CLASS_OF-2014))=9
group by stu_first, stu_last
order by total desc)
union
(select top 1  stu_first, stu_last, sum(KIND_hours) as total from STUDENT inner join KIND
on student.stu_id=KIND.stu_id
where (12-(STU_CLASS_OF-2014))=10
group by stu_first, stu_last
order by total desc)

stu_class_of是学生毕业的那一年

4 个答案:

答案 0 :(得分:0)

您的UNION不应该是2个子选择。您需要删除1个ORDER BY:

DECLARE @T1 TABLE (Id INT);
INSERT INTO @T1 VALUES (1), (2), (3);

DECLARE @T2 TABLE (Id INT);
INSERT INTO @T1 VALUES (7), (9), (-1);


SELECT * FROM @T1
UNION
SELECT * FROM @T2
ORDER BY Id DESC;


/* Output:
9 --From @T2
7 --From @T2
3
2
1
-1 --From @T2
*/

编辑:我现在意识到你真正想要的是什么。我应该通过看到你的TOP 1与UNION结合来实现。您实际需要的是CTE(公用表表达式)。这是您正在寻找的查询:

/*
SET IDENTITY_INSERT [STUDENT] ON;
INSERT INTO [STUDENT] (stu_id, stu_first, stu_last, STU_CLASS_OF) VALUES
(1,  'Leonard', 'Hofstadter', 1989),
(2, 'Sheldon', 'Cooper', 1989),
(3, 'Howard', 'Wolowitz', 1989),
(4, 'Raj', 'Koothrappali', 1989),
(5, 'Penny', '?', 2001),
(6, 'Bernadette', 'Rostenkowski ', 2001),
(7, 'Amy', 'Fowler', 2001)
SET IDENTITY_INSERT [STUDENT] OFF;

SET IDENTITY_INSERT [KIND] ON;
INSERT INTO [KIND] (stu_id, [hours]) VALUES
(1,  10),
(2, 13),
(3, 7),
(4, 54),
(5, 78),
(6, 13),
(7, 64)
SET IDENTITY_INSERT [KIND] OFF;
*/

WITH CTE AS (
    SELECT ROW_NUMBER() OVER (PARTITION BY [STU_CLASS_OF] ORDER BY SUM([KIND].[hours]) DESC) AS [RowNumber],
        [stu_first],
        [stu_last],
        SUM([KIND].[hours]) AS [total]
    FROM [STUDENT]
        INNER JOIN [KIND] ON [STUDENT].[stu_id] = [KIND].[stu_id]
    GROUP BY [stu_first], [stu_last], [STU_CLASS_OF]
)
SELECT
    [stu_first],
    [stu_last],
    [total]
FROM CTE
WHERE RowNumber = 1
ORDER BY [STU_CLASS_OF] DESC;

以下是对幕后实际情况的简短介绍: CTE就像一个子选择,但它有很多很棒的功能。其中一个是ROW_NUMBER(),每当它看到你在PARTION BY {something}中写的任何内容时都会给出一个ID。

但是,如果它随机发生,那么每次都会得到不同的结果。所以你还要为它添加一个ORDER BY,以便它知道哪些应该得到最低的ID。 在这种情况下,我们只对每个班级的1名学生感兴趣。所以我放入了[STU_CLASS_OF]。但是你也只想要各自的TOP。所以我按[total] DESC

订购

如果你想要,例如来自每个班级的TOP 3代替TOP 1,然后您只需将WHERE RowNumber = 1更改为3。

如果您只想要某些特定课程的数据而不是我想要的所有人,那么您只需将之前的WHERE子句添加到最终的SELECT中,如下所示:

WHERE RowNumber = 1
    AND (12 - ([STU_CLASS_OF] - 2014)) = 9
    AND (12 - ([STU_CLASS_OF] - 2014)) = 10

答案 1 :(得分:0)

试试这个:

进行2次查询.."派生"表。这是一个有效的Northwind示例:

  Use Northwind
     GO

Select  OrderID , CustomerID , EmployeeID from 
( Select TOP 1 OrderID , CustomerID , EmployeeID from  dbo.Orders where ShipCountry='France' Order by ShippedDate )
as derived1
UNION ALL
Select  OrderID , CustomerID , EmployeeID from 
( Select TOP 1 OrderID , CustomerID , EmployeeID from  dbo.Orders where ShipCountry='Germany' Order by ShippedDate  )
as derived2

这是插入您的查询,但我无法测试它们,因为我没有您的DDL。

    Select  * from 
    ( select top 1  stu_first, stu_last, sum(KIND_hours) as total from STUDENT inner join KIND
on student.stu_id=KIND.stu_id
where (12-(STU_CLASS_OF-2014))=9
group by stu_first, stu_last
order by total desc )
    as derived1
    UNION ALL
    Select  * from 
    ( select top 1  stu_first, stu_last, sum(KIND_hours) as total from STUDENT inner join KIND
on student.stu_id=KIND.stu_id
where (12-(STU_CLASS_OF-2014))=10
group by stu_first, stu_last
order by total desc  )
    as derived2

可能在周围工作的旧答案

如果您需要"按顺序排序"区分两组数据,你可以使用这个技巧:

IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
begin
        drop table #TableOne
end



IF OBJECT_ID('tempdb..#TableTwo') IS NOT NULL
begin
        drop table #TableTwo
end



CREATE TABLE #TableOne
( 
SurrogateKeyIDENTITY int not null IDENTITY (1,1) , 
NameOfOne varchar(12)
)



CREATE TABLE #TableTwo
( 
SurrogateKeyIDENTITY int not null IDENTITY (1,1) , 
NameOfTwo varchar(12)
)


Insert into #TableOne (NameOfOne)
Select 'C' as Alpha UNION ALL Select 'B' as Alpha UNION ALL Select 'D' as Alpha UNION ALL Select 'Z' as Alpha


Insert into #TableTwo (NameOfTwo)
Select 'T' as Alpha UNION ALL Select 'W' as Alpha UNION ALL Select 'X' as Alpha UNION ALL Select 'A' as Alpha



select 1 , NameOfOne from #TableOne
UNION
select 2 , NameOfTwo from #TableTwo
Order by 1 , 2 /* These are the "Ordinal Positions of the Column*/




IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
begin
        drop table #TableOne
end


IF OBJECT_ID('tempdb..#TableTwo') IS NOT NULL
begin
        drop table #TableTwo
end

答案 2 :(得分:0)

使用UNION时,您无法在子查询中使用ORDER BY。我确定有更好的解决方案,但将您的子查询包装在另一个级别将适合您。试试这个:

SELECT * FROM
(SELECT TOP 1 stu_first, stu_last, SUM(kind_hours) AS total 
 FROM student
 INNER JOIN kind ON student.stu_id = kind.stu_id
 WHERE (12-(stu_class_of-2014)) = 9
 GROUP BY stu_first, stu_last
 ORDER BY total DESC)

UNION

SELECT * FROM
(SELECT TOP 1 stu_first, stu_last, SUM(kind_hours) AS total 
 FROM student
 INNER JOIN kind ON student.stu_id = kind.stu_id
 WHERE (12-(stu_class_of-2014)) = 10
 GROUP BY stu_first, stu_last
 ORDER BY total DESC)

答案 3 :(得分:0)

每当我想订购一个子查询时,我倾向于将它包装在一个外部查询中:

select * from 
(select * from xx order by x) x

这样你可以在UNION或任何其他情况下嵌入这个查询,并且它总是有效,因为你在内部查询中应用了排序。