【问题标题】:SQL multiple select with multiple where condition带有多个 where 条件的 SQL 多选
【发布时间】:2014-05-17 14:02:33
【问题描述】:

我有一张简单的桌子

ID   usr_id       card_amount     state     created
----------------------------------------------------------------
1    a1          10.000            2      2014-03-13 14:33:39
2    a2          30.000            2      2014-03-11 14:33:39
3    a3          50.000            1      2014-03-10 14:33:39
4    a4          20.000            2      2014-04-13 14:33:39
5    a5          40.000            2      2014-03-19 14:33:39
----------------------------------------------------------------

我有这个查询,但它需要很长时间!帮我解决一下,让这更快

SELECT 
    DATE_FORMAT(`created`, '%Y-%m-%d') AS `key_date`,       
    (
        SELECT 
            SUM(`card_amount`) 
        FROM `payment` 
        WHERE `card_amount`> 0 AND `state` = 2 AND  `created` >= `key_date` AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) 
    ) AS `totalamount`,
    (
        SELECT 
            COUNT(`id`) 
        FROM `payment` 
        WHERE `card_amount`> 0 AND `state` =2 AND `created` >= `key_date` AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) 
    ) AS `turncharge`,
    (
        SELECT 
            COUNT(DISTINCT `usr_id`) 
        FROM `payment` 
        WHERE `card_amount`> 0 AND `state` =2 AND `created` >= `key_date` AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) 
    ) AS `pu`,
    (
        SELECT 
            SUM(`card_amount`) 
        FROM `payment` 
        WHERE `card_amount`> 0 AND `state` = 2 AND  `created` >= DATE_SUB(`key_date`,INTERVAL 6 DAY) AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) 
    ) AS `totalamount7`,            
    (
        SELECT 
            COUNT(`id`) 
        FROM `payment` WHERE `card_amount`> 0 AND `state` =2 AND `created` >= DATE_SUB(`key_date`,INTERVAL 6 DAY) AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY)  
    ) AS `turncharge7`,             
    (
        SELECT
            COUNT(DISTINCT `usr_id`) 
        FROM `payment` 
        WHERE `card_amount`> 0 AND `state` =2 AND `created` >= DATE_SUB(`key_date`,INTERVAL 6 DAY) AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) 
    ) AS `pu7`,
    (
        SELECT 
            SUM(`card_amount`) 
        FROM `payment` WHERE `card_amount`> 0 AND `state` = 2 AND  `created` >= DATE_SUB(`key_date`,INTERVAL 29 DAY) AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) 
    ) AS `totalamount30`,           
    (
        SELECT 
            COUNT(`id`) 
        FROM `payment` WHERE `card_amount`> 0 AND `state` =2 AND `created` >= DATE_SUB(`key_date`,INTERVAL 29 DAY) AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) 
    ) AS `turncharge30`,            
    (
        SELECT
            COUNT(DISTINCT `usr_id`) 
        FROM `payment` 
        WHERE `card_amount`> 0 AND `state` =2 AND `created` >= DATE_SUB(`key_date`,INTERVAL 29 DAY) AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) 
    ) AS `pu30`
FROM `payment`          
WHERE MONTH(`created`)=$month AND YEAR(`created`)=$year         
GROUP BY `key_date`         
ORDER BY `key_date` DESC

我使用 LEFT JOIN 但它没有给出我需要的东西:c1.totalamount = c2 totalmount7, c1.turncharge =c2.turncharge7 ........(不对)

SELECT DATE_FORMAT(`created`, '%Y-%m-%d') AS `key_date`,c1.totalamount,c1.turncharge,c1.pu,c2.totalamount7,c2.turncharge7,c2.pu7
FROM `payment` 

LEFT JOIN (SELECT DATE_FORMAT(`created`, '%Y-%m-%d') AS `date1`,SUM(`card_amount`) AS `totalamount`, COUNT(`id`) AS `turncharge`,COUNT(DISTINCT `usr_id`) AS `pu` 
FROM `payment` 
WHERE `card_amount`> 0 AND `state` = 2 AND  `created` >= DATE_FORMAT(`created`, '%Y-%m-%d')
AND `created` < DATE_SUB(DATE_FORMAT(`created`, '%Y-%m-%d'),INTERVAL -1 DAY)  GROUP BY date1) AS c1 ON date1 = DATE_FORMAT(`created`, '%Y-%m-%d')

LEFT JOIN (SELECT DATE_FORMAT(`created`, '%Y-%m-%d') AS `date2`,SUM(`card_amount`) AS `totalamount7`, COUNT(`id`) AS `turnchargep7`,COUNT(DISTINCT `usr_id`) AS `pu7` 
FROM `payment` 
WHERE `card_amount`> 0 AND `state` = 2 AND  created >= DATE_SUB(DATE_FORMAT(`created`, '%Y-%m-%d'),INTERVAL 6 DAY)   
AND `created` < DATE_SUB(DATE_FORMAT(`created`, '%Y-%m-%d'),INTERVAL -1 DAY) GROUP BY date2) AS c2 ON date2 = DATE_FORMAT(`created`, '%Y-%m-%d')

        WHERE MONTH(`created`)=4 AND YEAR(`created`)=2014
        GROUP BY `key_date`
        ORDER BY `key_date` DESC 

感谢 Mladen Prajdic 我使用 CASE 表达式,它工作得更快

SELECT date.key_date,
SUM(case when `card_amount`> 0 AND `state` = 2 AND  `created` >= `key_date` AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) then `card_amount` else 0 end) AS totalamount,
COUNT(DISTINCT(case  when `card_amount`> 0 AND `state` =2 AND `created` >= date.`key_date` AND `created` < DATE_SUB(date.`key_date`,INTERVAL -1 DAY) then payment.`id` else 0 end)) AS `turncharge`,
COUNT(DISTINCT(case  when `card_amount`> 0 AND `state` =2 AND `created` >= `key_date` AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY)  then `usr_id` else 0 end) )AS `pu` ,

SUM(case when `card_amount`> 0 AND `state` =2 AND `created` >= DATE_SUB(`key_date`,INTERVAL 6 DAY) AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) then `card_amount` else 0 end) AS `totalamount7`,
COUNT(DISTINCT(case  when `card_amount`> 0 AND `state` =2 AND `created` >= DATE_SUB(date.`key_date`,INTERVAL 6 DAY) AND `created` < DATE_SUB(date.`key_date`,INTERVAL -1 DAY)  then payment.`id` else 0 end)) AS `turncharge7`,
COUNT(DISTINCT(case  when `card_amount`> 0 AND `state` = 2 AND  `created` >= DATE_SUB(date.`key_date`,INTERVAL 6 DAY) AND `created` < DATE_SUB(date.`key_date`,INTERVAL -1 DAY)  then `usr_id` else 0 end) )AS `pu7` ,


SUM(case when `card_amount`> 0 AND `state` = 2 AND  `created` >= DATE_SUB(`key_date`,INTERVAL 29 DAY) AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY) then `card_amount` else 0 end) AS `totalamount30`,
COUNT(DISTINCT(case  when `card_amount`> 0 AND `state` = 2 AND  `created` >= DATE_SUB(date.`key_date`,INTERVAL 29 DAY) AND `created` < DATE_SUB(date.`key_date`,INTERVAL -1 DAY)  then payment.`id` else 0 end)) AS `turncharge30`,
COUNT(DISTINCT(case  when `card_amount`> 0 AND `state` = 2 AND  `created` >= DATE_SUB(`key_date`,INTERVAL 29 DAY) AND `created` < DATE_SUB(`key_date`,INTERVAL -1 DAY)  then `usr_id` else 0 end) )AS `pu30` 

FROM `payment`,(SELECT DATE_FORMAT(`created`, '%Y-%m-%d') AS `key_date` FROM `payment` 
WHERE MONTH(`created`)=3 AND YEAR(`created`)=2014
GROUP BY `key_date`) AS date

GROUP BY date.key_date
ORDER BY date.key_date DESC

【问题讨论】:

  • 当您进行这样的子选择时,它将永远花费很长时间,因为对于每个子选择,它必须与表中的每一行进行比较。因此,例如,如果您只有 1000 行付款,那么只需进行选择,就必须将每一行与 1000 行进行比较……进行 9000 次比较……甚至不考虑您在其中所做的所有其他事情。我建议为此查看多个查询,或进行联接。

标签: mysql sql database select where-clause


【解决方案1】:

用 case 语句重写您的相关子查询。 这将通过您的桌子一次。 本文如何展示:
Rewriting correlated sub-queries with CASE expressions

【讨论】:

    猜你喜欢
    • 2022-01-19
    • 1970-01-01
    • 2020-12-13
    • 1970-01-01
    • 2020-06-11
    • 2019-09-16
    • 2020-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多