2

假设我有一个surveys这样的表:

客户 | 上次调查结果 | 日期(整数)

CREATE TABLE `surveys` (
`id`  int(11) NOT NULL AUTO_INCREMENT ,
`customer`  int(11) NULL DEFAULT NULL ,
`survey_result`  tinyint(4) NOT NULL DEFAULT '-1' ,
`date`  smallint(2) NOT NULL ,
PRIMARY KEY (`id`),
INDEX `optimize` USING BTREE (`customer`, `survey_result`, `date`)
)
ENGINE=InnoDB
ROW_FORMAT=COMPACT
;

每个客户都可以进行多次评论。如果他没有完成它,last_survey_result=-1.

我想知道每个客户的最后评价是什么,以及不是-1。如果他从未回答过任何问题,则结果为默认值-1

例如,如果我们有这个

customer | survey_result | date (int)  
    a    |    -1         |     1
    a    |     7         |     2
    b    |    -1         |     1
    b    |    -1         |     2
    c    |    10         |     1
    c    |     8         |     2
    d    |    -1         |     1
    d    |     7         |     2

结果必须是:

customer | last_survey_result
    a    |       7
    b    |      -1
    c    |       8
    d    |       7

这是我尝试过的。事实上,它适用于这些数据:

SELECT a.customer, a.survey_result last_survey_result
  FROM surveys a
  LEFT OUTER JOIN surveys b
  ON a.customer=b.customer AND (a.date < b.date AND b.survey_result>=0)
  WHERE b.customer IS NULL 
GROUP BY customer;

SQL小提琴

问题出在示例中,我得到了很好的结果,但是在我的数据库中,这会发生:

customer | survey_result | date (int)  
    a    |    -1         |     1
    a    |     5         |     2
    a    |    -1         |     3
    b    |    -1         |     1
    b    |     8         |     2
    b    |    -1         |     3

customer | last_survey_result
    a    |       -1
    b    |        8

我认为这很奇怪,不知道会发生什么。它可能与索引有关吗?我完全迷路了。

4

4 回答 4

2

修改您的代码以分隔两种情况(至少一个非负结果 - 所有负结果):

SELECT a.customer, a.survey_result AS last_survey_result
  FROM surveys a
  LEFT OUTER JOIN surveys b
  ON a.customer = b.customer AND (a.date < b.date AND b.survey_result >= 0)
  WHERE a.survey_result >= 0 
    AND b.customer IS NULL 

UNION ALL

SELECT customer, -1
  FROM surveys
  GROUP BY customer
  HAVING MAX(survey_result) < 0 ;

SQL-Fiddle测试


这里还有另外两种方法可以做到这一点,没有UNION. 三重奏JOIN

-- solution 2 --
SELECT s.customer, 
       COALESCE(a.survey_result, -1) AS last_survey_result
  FROM 
      ( SELECT DISTINCT customer
        FROM surveys
      ) AS s
    LEFT JOIN
        surveys AS a
      JOIN 
        ( SELECT customer, MAX(date) AS date
          FROM surveys 
          WHERE survey_result >= 0 
          GROUP BY customer
        ) AS b
      ON  a.customer = b.customer 
      AND a.date = b.date 
    ON  s.customer = a.customer ;

和 a在子句JOIN中带有相关子查询:ON

-- solution 3 --
SELECT s.customer, 
       COALESCE(a.survey_result, -1) AS last_survey_result
  FROM 
      ( SELECT DISTINCT customer
        FROM surveys
      ) AS s
    LEFT JOIN
      surveys AS a
    ON  a.customer = s.customer 
    AND a.date =
        ( SELECT MAX(m.date)
          FROM surveys AS m
          WHERE m.customer = s.customer 
            AND m.survey_result >= 0 
        ) ;
于 2013-02-23T00:21:49.107 回答
1

事实证明这比看起来更难,至少对我来说......

SELECT DISTINCT a.customer, COALESCE((
  SELECT     b.survey_result
  FROM surveys b
  WHERE a.customer=b.customer AND b.survey_result <> -1
  ORDER BY date DESC LIMIT 1), -1) as last_result
FROM surveys a

这是通过 SQL Fiddle 提供的示例

CREATE TABLE surveys
    (`customer` varchar(1), `survey_result` int, `date` int)
;

INSERT INTO surveys
    (`customer`, `survey_result`, `date`)
VALUES
    ('a', -1, 1),
    ('a', 5, 2),
    ('a', -1, 3),
    ('b', -1, 1),
    ('b', 8, 2),
    ('b', -1, 3),
    ('c', -1, 1),
    ('c', -1, 2),
    ('c', -1, 3),
    ('d', 9, 1),
    ('d', 6, 2),
    ('d', 4, 3)
;

结果

CUSTOMER    LAST_RESULT
a           5
b           8
c           -1
d           4
于 2013-02-22T23:34:22.917 回答
1

只有在or子句GROUP BY中存在聚合函数时才有意义。SELECTHAVING

当您指定GROUP BY没有聚合函数的 a 时,大多数 RDBMS 都会出错,但 MySQL 不同。在 MySQL 中,子句起作用,但当不存在聚合函数时,它是不确定的。通常它会返回它找到的表中的第一个值,但由于 SQL 标准或 MySQL 文档中都没有记录这种行为,因此不能保证这种情况,因此假设是这种情况非常危险。

这将做你想要的:

SELECT DISTINCT
  a.customer,
  COALESCE(b.survey_result, -1) "last_survey_result"
FROM surveys as a
LEFT OUTER JOIN (
    SELECT customer,
      survey_result,
      date
    FROM surveys
    WHERE survey_result <> -1
    GROUP BY customer
    HAVING date = max(date)) as b
  ON a.customer = b.customer

请注意,您的 SQL Fiddle 返回了意外结果,因为您转置了客户“a”的datesurvey_results字段。

另请注意,这在大多数其他 RDBMS 中不起作用,因为子查询正在选择customer并且survey_result仅包含GROUP BY子句中的这两个字段之一。如果我没有时间紧迫,我可能会通过添加第三个自连接来将其重写为更合适的查询。

于 2013-02-22T23:44:46.413 回答
0

如果您不介意将结果作为字符字段返回,则以下内容将获取最新结果:

SELECT s.customer,
       substring_index(group_concat(s.survey_result order by date desc), ',', 1) last_survey_result
  FROM surveys s
where s.survey_result >= 0
GROUP BY customer;

你可以,当然cast是回到一个tinyint。

要获得所有客户,但只有积极的调查结果,请将条件移至案例:

SELECT s.customer,
       substring_index(group_concat((cast when s.survey_result >= 0 then s.survey_result end)
                                    order by date desc), ',', 1) last_survey_result
FROM surveys s
GROUP BY customer;

group_concat()忽略 NULL 值。

于 2013-02-22T23:52:15.190 回答