2

surveys次のようなテーブルがあるとします。

顧客 | last_survey_result | 日付 (整数)

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

コードを変更して 2 つのケースを分離します (少なくとも 1 つの非負の結果 - すべての負の結果):

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でテスト済み


を使わずに、さらに 2 つの方法があります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 ;

JOINで相関サブクエリを使用した a :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

は、 or句GROUP BYに集計関数が存在する場合にのみ意味があります。SELECTHAVING

集約関数なしでを指定すると、ほとんどの RDBMS はエラーになりますGROUP BYが、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

顧客 'a' のフィールドdateとフィールドを入れ替えたため、SQL Fiddle が予期しない結果を返したことに注意してください。survey_results

customerこれは、サブクエリが選択していて、句survey_resultにこれら 2 つのフィールドの 1 つしか含まれていないため、他のほとんどの RDBMS では機能しないことにも注意してください。GROUP BY時間がなければ、3 番目の自己結合を追加して、より適切なクエリになるように書き直します。

于 2013-02-22T23:44:46.413 に答える
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 に答える
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;

もちろん、casttinyint に戻すこともできます。

すべての顧客を取得し、肯定的な調査結果のみを取得するには、条件をケースに移動します。

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 に答える