根据行值从非唯一行中选择一行

时间:2014-06-20 12:32:15

标签: sql sql-server subquery case conditional-statements

我有一个测验表

id  | user_id | quiz_id
--------------------------
1   | 34567   | 12334
2   | 34567   | 12334
3   | 34567   | 23455

id 1和2描述了一个可以分配给同一个用户两次的测验

和一个测验交易表

id  | date | status
------------------------
1   | 2014 | assigned
2   | 2014 | assigned
3   | 2014 | assigned
------------------------
1   | 2014 | completed

id是测验表id的外键,最后一行描述用户完成测验时,事务表中的行更新状态为'completed'

预期结果:我想要一个像

这样的结构的表
id  | user_id| course_id | date | status
------------------------------------------
1   | 34567  | 12334     | 2014 | completed
2   | 32567  | 12334     | 2014 | assigned
3   | 2014   | 23455     | 2014 | assigned

我的查询是

SELECT  q.id, q.user_id, q.course_id, qt.date, qt.status FROM quiz q 
LEFT JOIN 
quiz_transaction qt  ON 
q.id = qt.id 

但它给了我额外的行(如查询所示)

1   | 34567  | 12334     | 2014 | assigned

我无法使用

ON qt.type = 'completed'

因为如果它完成了它应该返回一个已完成的行,如果不是,它应该返回一个指定的行,但不能返回两者。

所以在结果中我不能拥有

1   | 34567  | 12334     | 2014 | completed
1   | 34567  | 12334     | 2014 | assigned

我该怎么做?

3 个答案:

答案 0 :(得分:1)

如何简单地将MAX()功能与GROUP BYSQL Fiddle)一起使用:

SELECT  q.id, q.user_id, q.course_id, qt.date, MAX(qt.status) AS Status
FROM quiz q 
LEFT JOIN quiz_transaction qt ON q.id = qt.id 
GROUP BY q.id, q.user_id, q.course_id, qt.date

编辑:如果您需要以某种方式订购字符串,可以使用CASE语句将字符串转换为数字。获取MAX值,然后将其转换回来(SQL Fiddle):

SELECT m.id, m.user_id, m.quiz_id, MAX(m.date), 
  CASE WHEN MAX(m.status) =  1 THEN 'assigned'
       WHEN MAX(m.status) = 2 THEN 'doing'
       WHEN MAX(m.status) = 3 THEN 'completed' END AS Status
FROM 
(
  SELECT q.id, q.user_id, q.quiz_id, qt.date, 
  CASE WHEN qt.status = 'assigned' THEN 1 
       WHEN qt.status = 'doing' THEN 2
       WHEN qt.status = 'completed' THEN 3 END AS Status
  FROM quiz q 
  LEFT JOIN quiz_transaction qt ON q.id = qt.id 
) AS m
GROUP BY m.id, m.user_id, m.quiz_id;

答案 1 :(得分:1)

根据您的版本,SQLnServer支持标准SQL的“窗口聚合函数”。 ROW_NUMBER将为您提供一行:

SELECT
   q.id
  ,q.user_id
  ,q.quiz_id
  ,qt.date
  ,qt.status
FROM quiz q 
JOIN 
 (
   SELECT
     id
     ,date
     ,status
     ,ROW_NUMBER()
      OVER (PARTITION BY id
            ORDER BY Status DESC) as rn
   FROM quiz_transaction
 ) as qt
ON q.id = qt.id
WHERE rn = 1 

如果你有更复杂的订购规则,你需要使用CASE:

     ,ROW_NUMBER()
      OVER (PARTITION BY id
            ORDER BY CASE Status WHEN 'completed' THEN 1 
                                 WHEN 'doing'     THEN 2
                                 WHEN 'assigned'  THEN 3
                     END) as rn

答案 2 :(得分:0)

试试这个

SELECT  q.id, q.user_id, q.course_id, q1.date, qt.status FROM quiz q 
         LEFT JOIN 
    (Select id , convert(varchar,max(convert(varbinary,status )))  'Status'
     from     quiz_transaction
    group by id
    ) qt  ON 
         q.id = qt.id 
    left join quiz_transaction q1 on q1.id = qt.id and q1.status=qt.status