2016-11-16 8 views
0

私は次のクエリを持っています。ここでは、特定のアイテムについて、売上の数とその日の売上の平均価格を取得します。グループを使用しているときに内部結合フィールドの中央値を計算する方法は?

SELECT COUNT(1) AS num_sales, DATE_FORMAT(sales.created_at, '%Y-%m-%d') AS date, AVG(prices.price) AS avg_price 
FROM sales INNER JOIN prices ON prices.id = sales.price_id 
WHERE prices.item_id = 7503 AND (`prices`.`source` = 0 or (`prices`.`price` >= 400 and `prices`.`source` > 0)) 
GROUP BY date 
ORDER BY date ASC 

私はまた、forループ(のは、結果の数が偶数あると仮定しましょう)中間価格を取得するために、日ごとに別々のクエリを実行します:

SELECT prices.price FROM sales INNER JOIN prices ON prices.id = sales.price_id 
WHERE prices.item_id = 7503 
AND (`prices`.`source` = 0 or (`prices`.`price` >= 400 and `prices`.`source` > 0)) 
AND DATE(sales.created_at) = "<THE DATE OF THE CURRENT FOR-LOOP OBJECT>" 
ORDER BY prices.price ASC 
LIMIT 1 OFFSET <NUMBER OF THE MIDDLE ROW> 

あなたが想像できるように、いくつかのケースでは、大規模なテーブルで何百ものクエリを実行する必要があるため(販売テーブルには数億行があります)、これは非常に遅いです。

prices.priceの中央値も計算するように、最初のSQLクエリを書き直す方法は、AVG(prices.price)に似ていますか?私はthis oneのような答えを見てきましたが、私の特定のシナリオのためにそれをどのように適応させるかについて私の頭を包み込むことはできません。

これを達成するのに何時間も費やしましたが、私のSQL知識だけでは十分ではありません。どんな助けでも大歓迎です!

[email protected]:~# mysql -V 
mysql Ver 14.14 Distrib 5.7.13, for Linux (x86_64) using EditLine wrapper 

テーブルスキーマ:私の最初のクエリからの出力の

CREATE TABLE `prices` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`item_id` int(11) unsigned NOT NULL, 
`price` decimal(8,2) NOT NULL, 
`net_price` decimal(8,2) NOT NULL, 
`source` tinyint(4) NOT NULL, 
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
PRIMARY KEY (`id`), 
UNIQUE KEY `id` (`id`), 
KEY `prices_ibfk_1` (`item_id`), 
CONSTRAINT `prices_ibfk_1` FOREIGN KEY (`item_id`) REFERENCES `items` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=4861375 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

CREATE TABLE `sales` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`price_id` int(11) unsigned DEFAULT NULL, 
`item_key` varchar(40) COLLATE utf8_unicode_ci NOT NULL, 
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
PRIMARY KEY (`id`), 
UNIQUE KEY `id` (`id`), 
UNIQUE KEY `item_key` (`item_key`), 
KEY `price_id` (`price_id`), 
KEY `created_at` (`created_at`), 
KEY `price_id__created_at__IX` (`price_id`,`created_at`), 
CONSTRAINT `sales_ibfk_1` FOREIGN KEY (`price_id`) REFERENCES `prices` (`id`) ON UPDATE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=386156944 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 

例:

Example of output from my first query

+0

あなたのショーがテーブル出力 – e4c5

+0

を作成して投稿し共有してください - 価格のデータ型を? 1日あたりの最大行数 –

+0

@ e4c5 create tableの出力を追加しました。 1日あたりの最大行数は、記録された売上数によって異なります。これは数十万になる可能性があります。 – waylaidwanderer

答えて

0

私は、大規模な検索後、私の質問hereへの答えを見つけました。おそらく私は最初に私の質問に言及しなかったでしょう。

私は私自身のケースの解決策を適応している、とここでの作業クエリです:

SELECT COUNT(1) AS num_sales, 
     DATE_FORMAT(sales.created_at, '%Y-%m-%d') AS date, 
     AVG(prices.price) AS avg_price, 
     CASE(COUNT(1) % 2) 
     WHEN 1 THEN SUBSTRING_INDEX(
      SUBSTRING_INDEX(
       group_concat(prices.price 
          ORDER BY prices.price SEPARATOR ',') 
       , ',', (count(*) + 1)/2) 
      , ',', -1) 
     ELSE (SUBSTRING_INDEX(
       SUBSTRING_INDEX(
        group_concat(prices.price 
            ORDER BY prices.price SEPARATOR ',') 
        , ',', count(*)/2) 
       , ',', -1) 
      + SUBSTRING_INDEX(
       SUBSTRING_INDEX(
        group_concat(prices.price 
            ORDER BY prices.price SEPARATOR ',') 
        , ',', (count(*) + 1)/2) 
       , ',', -1))/2 
     END median_price 
FROM sales 
    INNER JOIN prices ON prices.id = sales.price_id 
WHERE prices.item_id = 7381 
     AND (`prices`.`source` = 0 
      OR (`prices`.`price` >= 400 
       AND `prices`.`source` > 0)) 
GROUP BY date 
ORDER BY date ASC; 
関連する問題