1

何度も失敗した後、理解できないように見える問題があります。

レポートのために結合する必要がある 3 つのテーブルがあり、3 番目のテーブルにはレコードが存在しない可能性があります。しかし、3 番目のテーブルのレコードが存在しない場合は、3 番目のテーブルからのデータに対して null 値を報告し、他の条件に一致するすべてのレコードを取得する必要があります。

関連する列に切り詰めると、テーブル構造は次のようになります。

members -このテーブルは、ウェブサイトに登録するすべてのメンバーを保持します

| memberId  | insertDate          |
| ==========|=====================|
| 1         | 2013-08-01 18:18:16 |
| 2         | 2013-08-02 18:18:16 |
| 3         | 2013-08-03 18:18:16 |
| 4         | 2013-08-04 18:18:16 |
| 5         | 2013-08-05 18:18:16 |

registration_steps -このテーブルは、登録プロセスの進行状況と、登録が完了したかどうかを保持します

| memberId  | completed |
| ==========|===========|
| 1         | 1         |
| 2         | 1         |
| 3         | 1         |
| 4         | 0         |
| 5         | 1         |

購入-このテーブルは、まあ..購入を保持します

| memberId  | insertDate          |
| ==========|=====================|
| 1         | 2013-08-02 18:18:16 |
| 1         | 2013-08-03 17:18:16 |
| 1         | 2013-08-03 18:18:16 |
| 5         | 2013-08-07 18:18:16 |

これは私がこれまでに思いついたクエリです:

SELECT `m`.`memberId`,
       DATE(`m`.`insertDate`) AS `regDate`,
       COUNT(`p`.`memberId`) AS `totalTransactions`,
       DATE(MIN(`p`.`insertDate`)) AS `firstPurchaseDate`,
       DATE(MAX(`p`.`insertDate`)) AS `latestPurchaseDate`,
       DATEDIFF(DATE(MIN(`p`.`insertDate`)), DATE(`m`.`insertDate`)) AS `daysBetweenRegAndFirstPurchase`
  FROM `db`.`members` `m`
       INNER JOIN `db`.`registration_steps` `r` ON `m`.`memberId` = `r`.`memberId` 
       INNER JOIN `db`.`purchases` `p` ON `m`.`memberId` = `p`.`memberId`
 WHERE `m`.`insertDate` BETWEEN '2013-07-01 00:00:00' AND '2013-07-31 23:59:59'
   AND `r`.`completed` = 1
GROUP BY `m`.`memberId`
;

必要なものはすべて表示されますが、テーブル購入のレコードが欠落しているメンバーは表示されません。

ここに私が得るものがあります:

| memberId  | regDate             | totalTransactions | firstPurchaseDate   | latestPurchaseDate  | daysBetweenRegAndFirstPurchase |
| ==========|=====================|===================|=====================|=====================|================================|
| 1         | 2013-08-01 18:18:16 | 3                 | 2013-08-02 18:18:16 | 2013-08-03 18:18:16 | 1                              |
| 5         | 2013-08-05 18:18:16 | 1                 | 2013-08-07 18:18:16 | 2013-08-07 18:18:16 | 2                              |

しかし、私が必要とするのは:

| memberId  | regDate             | totalTransactions | firstPurchaseDate   | latestPurchaseDate  | daysBetweenRegAndFirstPurchase |
| ==========|=====================|===================|=====================|=====================|================================|
| 1         | 2013-08-01 18:18:16 | 3                 | 2013-08-02 18:18:16 | 2013-08-03 18:18:16 | 1                              |
| 2         | 2013-08-02 18:18:16 | 0                 | NULL                | NULL                | -1                             |
| 3         | 2013-08-03 18:18:16 | 0                 | NULL                | NULL                | -1                             |
| 5         | 2013-08-05 18:18:16 | 1                 | 2013-08-07 18:18:16 | 2013-08-07 18:18:16 | 2                              |

これを実現するために、2 番目の内部結合を左結合、左外部結合に変更し、最初の内部結合条件に where 条件を配置しようとしました。しかし、私は望ましい結果を得ることができませんでした。(ただし、実際のシナリオでのメンバーの合計数は約 20k です)。

誰?

前もって感謝します!

4

3 に答える 3

3

テーブルからすべての結果を取得するには、他のテーブルmemberに必要な結果をleft joinテーブルに追加group bymemberます。

サンプル

FROM `db`.`members` `m`
       LEFT OUTER JOIN `db`.`registration_steps` `r` ON `m`.`memberId` = `r`.`memberId` 
       LEFT OUTER JOIN `db`.`purchases` `p` ON `m`.`memberId` = `p`.`memberId`

左[アウター]

結合条件を満たさない左側のテーブルのすべての行が結果セットに含まれ、内部結合によって返されるすべての行に加えて、他のテーブルの出力列が NULL に設定されることを指定します。

于 2013-08-24T05:18:17.320 に答える
2

(クエリの日付範囲が 2013-07 ではなく 2013-08 の間であると仮定します)。購入に対する結合を外部結合に切り替える必要があります。これには購入のないメンバーが含まれますので...

   left outer JOIN `purchases` `p` ON `m`.`memberId` = `p`.`memberId`

SQL フィドル

于 2013-08-24T05:18:06.403 に答える
0

(内部結合を左結合に置き換えると、正しい結果が得られます)

からdbmembers m 左結合dbregistration_steps rオンmmemberId= r. memberId 左結合dbpurchases pオンmmemberId= p.memberId

または、任意の購入を単独で左結合に置き換えることができます。

注: 左結合と左外部結合はどちらも同じ結果を生成するため、いずれかを使用できます。

于 2013-08-24T05:42:29.867 に答える