【问题标题】:How to find out customers that only shopped in one store using SQL如何使用 SQL 找出只在一家商店购物的客户
【发布时间】:2016-11-09 01:02:25
【问题描述】:

我想查看特定时期内只在一家特定商店购物的顾客数量,所以我写了如下 SQL:

SELECT COUNT (DISTINCT CARD_NUMBER)
FROM <TRANSACTION TABLE>
WHERE DATE BETWEEN ‘XXXX-XX-XX’(DATE) AND ‘XXXX-XX-XX’(DATE)
AND STORE_NUMBER = 1234;

如果这些客户(持卡人)在其他连锁店购物怎么办?

我无法使用 AND CARD_NUMBER NOT IN… 因为我们的店太多了。 任何可以在这里使用的语法来解决这个问题?

【问题讨论】:

  • 考虑使用NOT EXISTS 谓词。事实上,许多数据库优化器会将NOT IN (...) 重写为NOT EXISTS。或者,您可以将 LEFT OUTER JOIN 返回到存储编号 1234 的事务表,并将 WHERE checkTable.column is null 添加到 where 子句。
  • mysqlteradata?

标签: mysql sql teradata


【解决方案1】:

如果所有交易都在一个商店中,那么 MIN 和 MAX 是相同的:

SELECT COUNT(*)
FROM
 ( 
   SELECT CARD_NUMBER
   FROM <TRANSACTION TABLE>
   WHERE DATE BETWEEN ‘XXXX-XX-XX’(DATE) AND ‘XXXX-XX-XX’(DATE)
   GROUP BY CARD_NUMBER
   HAVING MIN(STORE_NUMBER) = 1234  -- shopped in this store
       AND MAX(STORE_NUMBER) = 1234  -- but no other store 
 ) dt;

【讨论】:

    【解决方案2】:

    如果我理解您的问题,您想知道在给定时间段内有多少客户仅在商店 1234 购物。

    我认为这样做:

    SELECT COUNT (DISTINCT CARD_NUMBER)
      FROM <TABLE>
     WHERE DATE BETWEEN ‘XXXX-XX-XX’(DATE) AND ‘XXXX-XX-XX’(DATE)
       AND STORE_NUMBER = 1234
       AND CARD_NUMBER NOT IN (SELECT DISTINCT CARD_NUMBER
                                 FROM <TABLE>
                                WHERE DATE BETWEEN ‘XXXX-XX-XX’(DATE)
                                               AND ‘XXXX-XX-XX’(DATE)
                                  AND STORE_NUMBER <> 1234);
    

    子选择会为您提供在该时间段内在其他地方购物的卡号列表。因此,您的意思是,“向我显示商店 1234 的给定日期的所有卡号,其中该号码未出现在其他商店使用的卡号列表中。”

    希望有帮助

    【讨论】:

    • 这里的问题是他说:I couldn’t use AND CARD_NUMBER NOT IN… Because we have too many stores
    • 我认为这意味着他无法枚举所有这些,并且也许他不知道子选择。无论如何,下面@dnoeth 提供的答案更好。 :-) 直到我发布我的之后才看到它。
    • 取决于数据库的大小和可用的排序空间量。如果数据集太大,group by 可能会破坏一些较小框上的排序空间。
    • 如果 CARD_NUMBER 可以为空,则可能不会返回任何行。你应该添加and CARD_NUMBER IS NOT NULL
    【解决方案3】:

    在您的 NOT IN 子句中添加另一个选择语句 ... AND NOT IN (SELECT DISTINCT STORE_NUMBER FROM FOO WHERE STORE_NUMBER != 1234)

    【讨论】:

      【解决方案4】:

      正如我在评论中提到的,许多数据库优化器会将NOT IN (...) 重写为NOT EXISTS。在您的情况下,NOT EXISTSLEFT OUTER JOIN 都可以使用...

      使用NOT EXISTS

      SELECT COUNT (DISTINCT CARD_NUMBER)
      FROM <TRANSACTION TABLE> T
      WHERE DATE BETWEEN ‘XXXX-XX-XX’(DATE) AND ‘XXXX-XX-XX’(DATE)
      AND NOT EXISTS (
        SELECT 1
        FROM <TRANSACTION TABLE> T
        WHERE DATE BETWEEN ‘XXXX-XX-XX’(DATE) AND ‘XXXX-XX-XX’(DATE)
        AND STORE_NUMBER <> 1234
      )
      AND STORE_NUMBER = 1234;
      

      使用LEFT OUTER JOIN

      SELECT COUNT (DISTINCT CARD_NUMBER)
      FROM <TRANSACTION TABLE> T
      LEFT OUTER JOIN  <TRANSACTION TABLE> CHECK
          ON  T.CARD_NUMBER = CHECK.CARD_NUMBER
          AND CHECK.DATE BETWEEN ‘XXXX-XX-XX’(DATE) AND ‘XXXX-XX-XX’(DATE)
          AND STORE_NUMBER <> 1234
      WHERE T.DATE BETWEEN ‘XXXX-XX-XX’(DATE) AND ‘XXXX-XX-XX’(DATE)
      AND T.STORE_NUMBER = 1234
      AND CHECK.CARD_NUMBER IS NULL;
      

      【讨论】:

        【解决方案5】:
        With card_list as (
        -- get the custs that shopped 1234
        select CARD_NUMBER
        FROM <TRANSACTION TABLE>
        WHERE DATE BETWEEN ‘XXXX-XX-XX’(DATE) AND ‘XXXX-XX-XX’(DATE)
        AND STORE_NUMBER = 1234
        
        EXCEPT
        -- Remove from the above list those that shopped other stores
        
        -- get the custs that shopped all other stores
        select CARD_NUMBER
        FROM <TRANSACTION TABLE>
        WHERE DATE BETWEEN ‘XXXX-XX-XX’(DATE) AND ‘XXXX-XX-XX’(DATE)
        AND STORE_NUMBER <> 1234
        )
        
        -- get the counts, this is already a unique list so no distinct needed.
        select count(CARD_NUMBER) from card_list;'
        

        【讨论】:

          【解决方案6】:
          SELECT COUNT(*)
          FROM
           ( 
             SELECT CARD_NUMBER
              FROM <TRANSACTION TABLE>
              WHERE DATE BETWEEN ‘XXXX-XX-XX’(DATE) AND ‘XXXX-XX-XX’(DATE)
              AND STORE_NUMBER = '1234'
              GROUP BY CARD_NUMBER
              HAVING COUNT(CARD_NUMBER) = 1
            ) dt;
          

          【讨论】:

          • 这会检查在该特定商店仅购物一次但不涉及其他商店或多次购买的客户。
          • @dnoeth 或许 COUNT(DISTINCT STORE_NUMBER) =1 然后
          • @ConradFrix:不,这将始终返回1,因为STORE_NUMBER = '1234' 上有一个 WHERE 条件
          • @dnoeth doh :) 我想你可以将 `STORE_NUMBER = '1234' 移到内联视图之外。例如,首先找到仅在一家商店中使用的所有卡。现在将其限制为仅存储 1234
          • @ConradFrix:当然有办法解决它,这就是我写第一条评论的原因(顺便说一句,我没有投反对票)。最后它会和我的回答很相似:)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-11-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多