4

Mysql でサブクエリを理解するのに苦労しています。かなり単純なものは問題ありません。私が見つけたほとんどのチュートリアルは、典型的なものを超えることはめったにありません。

SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);

私がデータベースから引き出そうとしているのは次のとおりです(私たちのデータベースの背景なしでこれを説明するために最善を尽くします):

特定の担当者に属する顧客のリストと、先月の合計支出額 (1 つの列) と、1 か月間の支出額 (別の列) を取得します。

結果として、これはおおよそ次のようになります。

ID | NAME   | PREV MONTH | CUR MONTH
1  | foobar | £2300      | £1200
2  | barfoo | £1240      | £500

データの最初の部分を取得するために使用しているクエリは次のとおりです。

SELECT c.id,c.name, SUM(co.invoicetotal) as total
FROM customers as c
JOIN customerorders as co on co.customer_id = c.id
WHERE c.salesrep_id = 24
AND co.orderdate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND CURDATE()
GROUP by c.id
order by total desc

DATE_SUB は実際の日付に置き換えることができます。これは、最終的に PHP 変数がここに移動するためです。例として、これは有効なデータを提供します。

これにより、たとえば次のようになります。

ID | NAME   | TOTAL 
1  | foobar | £2300      
2  | barfoo | £1240   

したがって、理想的には、私のサブクエリはこれとまったく同じクエリですが、日付が変更されています。エラーが発生し続け#1242 - Subquery returns more than 1 row ます。

提案やアドバイスをお願いします。

前もって感謝します。ロブ

4

5 に答える 5

5
SELECT  c.id, c.name,
        (
        SELECT  SUM(co.invoicetotal)
        FROM    customerorders co
        WHERE   co.customer_id = c.id
                AND co.orderdate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND CURDATE()
        ) AS prev_month,
        (
        SELECT  SUM(co.invoicetotal)
        FROM    customerorders co
        WHERE   co.customer_id = c.id
                AND co.orderdate BETWEEN CURDATE() AND CURDATE() + INTERVAL 1 MONTHS
        ) AS cur_month,
FROM    customers as c
WHERE   c.salesrep_id = 24
ORDER BY
        prev_month DESC
于 2010-08-16T16:16:30.020 に答える
1

コードから生成しているため、日付の計算は省略しています。

SELECT c.id,c.name, 
    SUM(case when co.orderdate >= @LastMonthStartDate and co.orderdate < @CurrentMonthStartDate then co.invoicetotal else 0 end) as LastMonthTotal,
    SUM(case when co.orderdate between @CurrentMonthStartDate and CURDATE() then co.invoicetotal else 0 end) as CurrentMonthTotalToDate
FROM customers as c 
JOIN customerorders as co on co.customer_id = c.id 
WHERE c.salesrep_id = 24 
   AND co.orderdate BETWEEN @LastMonthStartDate AND CURDATE() --remove this if you want customers that did not order in the last 2 months
GROUP by c.id 
order by total desc 
于 2010-08-16T16:17:34.437 に答える
1

エラーが発生する理由は次のとおりです。

WHERE column1 = (SELECT column1 FROM t2)

t2.column1は複数の結果を返していますが、サブクエリの前に equals 演算子があるため、受け入れられる値は1 つだけです。

そのため、IN に変更する必要があります。

WHERE column1 IN (SELECT column1 FROM t2)

...複数の値を受け入れる。または、1 つの変数のみを返すようにサブクエリを変更します。この例ではt2.column1、テーブル全体の最高値を返します。

WHERE column1 = (SELECT MAX(column1) FROM t2)

それはすべて、取得しようとしているデータに依存します。

于 2010-08-16T16:13:53.417 に答える
0

JacobMに同意しますが、少し異なるアプローチを考え出しました。

SELECT
    c.id,
    c.name, 
    SUM(co1.invoicetotal) as PREV_MONTH, 
    SUM(co2.invoicetotal) as CUR_MONTH, 
FROM
    customers as c, 
    customerorders as co1, 
    customerorders as co2
WHERE 
    c.salesrep_id = 24
    and  co1.customer_id = c.id
    and  co2.customer_id = c.id
    AND co1.orderdate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND CURDATE()
    AND co2.orderdate > DATE_SUB(CURDATE(), INTERVAL 30 DAY)
GROUP by c.id
order by total desc

どちらがより効率的かわからない。

于 2010-08-16T16:40:55.067 に答える
0

OMG Ponies は、そのエラーが発生した理由について正しいです。比較で使用されるサブクエリは、常に単一の値を返す必要があります。

私の推測では、2 つのサブクエリ (1 つは prev 用、もう 1 つは curr 用) を作成し、それらをユーザー ID で結合する必要があると思います。このようなもの:

SELECT prev.id,prev.name, prev.total, curr.total
FROM
(
SELECT c.id,c.name, SUM(co.invoicetotal) as total  
FROM customers as c JOIN customerorders as co on co.customer_id = c.id  
WHERE c.salesrep_id = 24  
AND co.orderdate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND CURDATE()  
GROUP by c.id ORDER BY total desc  
) as prev
JOIN
(
SELECT c.id,c.name, SUM(co.invoicetotal) as total  
FROM customers as c JOIN customerorders as co on co.customer_id = c.id  
WHERE c.salesrep_id = 24  
AND co.orderdate > CURDATE()
GROUP by c.id ORDER BY total desc  
) as curr
ON prev.id=curr.id
于 2010-08-16T16:17:18.960 に答える