30

毎日の株価(始値、高値、安値、終値、出来高)で構成されるMySqlテーブルがあり、その場で週次データに変換しようとしています。これまでのところ、高値、安値、音量で機能する次の機能があります。

SELECT MIN(_low), MAX(_high), AVG(_volume),
CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
FROM mystockdata
GROUP BY myweek
ORDER BY _date;

上記のクエリで_openの最初のインスタンスを選択する必要があります。したがって、たとえば、月曜日(特定の週)に休日があり、火曜日に株式市場が開かれた場合、_open値は、その週にグループ化された火曜日から選択する必要があります。同様に、終値はその週の最後の_closeである必要があります。

MySqlでFIRST()やLAST()のようなものを選択して、ネストされたselectクエリを使用するのではなく、上記を1つのSELECT内にまとめることはできますか?

スキーマを理解するためのテーブルのcreateステートメントは次のとおりです。

delimiter $$
CREATE TABLE `mystockdata` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `symbol_id` int(11) NOT NULL,
  `_open` decimal(11,2) NOT NULL,
  `_high` decimal(11,2) NOT NULL,
  `_low` decimal(11,2) NOT NULL,
  `_close` decimal(11,2) NOT NULL,
  `_volume` bigint(20) NOT NULL,
  `add_date` date NOT NULL,
  PRIMARY KEY (`id`),
  KEY `Symbol_Id` (`symbol_id`,`add_date`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8$$

更新:nullはありません。休日/週末がある場合は常に、テーブルにはその日付のレコードがありません。

4

4 に答える 4

50

MySQL 8を使用している場合、推奨されるソリューションは、現在使用可能なウィンドウ関数FIRST_VALUE()および/またはLAST_VALUE()を使用することです。LukasEderの答えを見てください。

ただし、古いバージョンのMySQLを使用している場合、これらの関数はサポートされていません。ある種の回避策を使用してそれらをシミュレートする必要があります。たとえば、forとforによって順序付けられた週のすべてと値のセットを作成し、の最初の要素を抽出する集約文字列関数GROUP_CONCAT()を利用できます。セットする:_open_close_date_open_date desc_close

select
  min(_low),
  max(_high),
  avg(_volume),
  concat(year(_date), "-", lpad(week(_date), 2, '0')) AS myweek,
  substring_index(group_concat(cast(_open as CHAR) order by _date), ',', 1 ) as first_open,
  substring_index(group_concat(cast(_close as CHAR) order by _date desc), ',', 1 ) as last_close
from
  mystockdata
group by
  myweek
order by
  myweek
;

LIMIT 1別の解決策は、SELECT句内のサブクエリを利用します。

select
  min(_low),
  max(_high),
  avg(_volume),
  concat(year(_date), "-", lpad(week(_date), 2, '0')) AS myweek,
  (
    select _open
    from mystockdata m
    where concat(year(_date), "-", lpad(week(_date), 2, '0'))=myweek
    order by _date
    LIMIT 1
  ) as first_open,
  (
    select _close
    from mystockdata m
    where concat(year(_date), "-", lpad(week(_date), 2, '0'))=myweek
    order by _date desc
    LIMIT 1
  ) as last_close
from
  mystockdata
group by
  myweek
order by
  myweek
;

LPAD()文字列関数をに追加myweekして、週番号を常に2桁の長さにすることに注意してください。そうしないと、週が正しく順序付けられません。

また、substring_indexをgroup_concat()と組み合わせて使用​​する場合も注意してください。グループ化された文字列のいずれかにコンマが含まれていると、関数が期待どおりの結果を返さない場合があります。

于 2012-12-19T16:54:05.240 に答える
8

MySQL 8以降では、理想的にはタスクにウィンドウ関数を使用します。

WITH 
  t1 AS (
    SELECT _low, _high, _volume, CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
    FROM mystockdata
  ),
  t2 AS (
    SELECT 
      t1.*, 
      FIRST_VALUE(_open) OVER (PARTITION BY myweek ORDER BY _date) AS first_open,
      FIRST_VALUE(_close) OVER (PARTITION BY myweek ORDER BY _date DESC) AS last_close
    FROM t1
  )
SELECT MIN(_low), MAX(_high), AVG(_volume), myweek, MIN(first_open), MAX(last_close)
FROM t2
GROUP BY myweek
ORDER BY myweek;
于 2018-09-19T19:00:45.143 に答える
2

COALESCE最初の値を取得するには、関数を使用する必要があります。ただし、データのない日(週末と祝日)のデータがない日はnull値になるようにする必要があり_openます。

使用法は次のようになります。

SELECT MIN(_low), MAX(_high), AVG(_volume), COALESCE(_open)
CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
FROM mystockdata
GROUP BY myweek
ORDER BY _date;

last()値については、かなりハッキーな解決策しか考えられません。これはGROUP_CONCAT、リストから最後の値を取得するために文字列操作を使用することです。したがって、おそらく次のようなものです。

SELECT MIN(_low), MAX(_high), AVG(_volume), COALESCE(_open), SUBSTRING_INDEX(GROUP_CONCAT(_close), ',', -1)
CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
FROM mystockdata
GROUP BY myweek
ORDER BY _date;

GROUP_CONCAT一貫性のあるクエリが必要な場合は、合体の代わりに最初のアイテムにアプローチを使用することもできます。

SELECT MIN(_low), MAX(_high), AVG(_volume), SUBSTRING_INDEX(GROUP_CONCAT(_open), ',', 1), SUBSTRING_INDEX(GROUP_CONCAT(_close), ',', -1)
CONCAT(YEAR(_date), "-", WEEK(_date)) AS myweek
FROM mystockdata
GROUP BY myweek
ORDER BY _date;

GROUP_CONCAT正しく機能するためには、値のない日付のフィールドがnullであることも確認する必要があり_openます_close

于 2012-12-19T16:51:25.690 に答える
-1

基本的に、あなたがする必要があること:

  1. PRODUCTIDによるグループ化
  2. 各グループ内で、LOCATIONで注文
  3. LOCATIONで注文したものと同じ製品の最初の価格を選択します

それらをまとめると、次のクエリを使用できます。

SELECT PRODUCTID, 
   SUBSTRING_INDEX(GROUP_CONCAT(CAST(LOCATION AS CHAR) ORDER BY LOCATION DESC), ',', 1) AS LOCATION,
   SUBSTRING_INDEX(GROUP_CONCAT(CAST(PRICE AS CHAR) ORDER BY LOCATION DESC), ',', 1) AS PRICE
FROM ProductLocation
GROUP BY PRODUCTID;

MySQLにはGROUPBY用のFIRST()およびLAST()集計関数がありませんが、そのようなFIRST()およびLAST()は、GROUP_CONCAT()およびSUBSTRING_INDEX()関数を使用してシミュレートできることに注意してください。

于 2015-05-21T22:17:51.630 に答える