2011-12-16 8 views
3

I次のSQL Server 2008のクエリがあります。これは、基本的にT内のすべてのレコードのための最終E値を取得しますが、MySQLは - Timeで最後のエントリを取得します(または最初の場合はnull)

SELECT T.*,Data.Value FROM [Table] T OUTER APPLY  

(SELECT TOP 1 E.Value FROM [Table2] E  
ORDER BY CASE WHEN T.TDateTime >= E.EDateTime then 1 else 2 end, 
ABS(DateDiff(ss,T.TDateTime,E.EDatetime))) AS Data 

をレコード内の場合Tは、Eの最初のレコードの前にあり、Eの最初のレコードを取得します。

MySQLには何が相当しますか?ここで

EDIT


は私のスキーマとデータです:

DROP TABLE IF EXISTS `data`; 
CREATE TABLE `data` (
    `ID` int(11) NOT NULL AUTO_INCREMENT, 
    `DataDateTime` datetime DEFAULT NULL, 
    `Value` int(11) DEFAULT NULL, 
    PRIMARY KEY (`ID`) 
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; 


LOCK TABLES `data` WRITE; 
INSERT INTO `data` VALUES (1,'2012-02-01 00:00:00',1),(2,'2012-03-01 01:00:00',2),(3,'2012-04-01 02:00:00',3),(4,'2012-05-01 03:00:00',4),(5,'2012-06-01 04:00:00',5),(6,'2012-07-01 05:00:00',6),(7,'2012-08-01 06:00:00',7),(8,'2012-09-01 07:00:00',8); 
UNLOCK TABLES; 


DROP TABLE IF EXISTS `t`; 
CREATE TABLE `t` (
    `ID` int(11) NOT NULL AUTO_INCREMENT, 
    `TDateTime` datetime DEFAULT NULL, 
    PRIMARY KEY (`ID`) 
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; 

LOCK TABLES `t` WRITE; 
INSERT INTO `t` VALUES (1,'2012-01-01 00:00:00'),(2,'2012-02-01 00:00:00'),(3,'2012-02-01 12:00:00'),(4,'2012-03-01 00:00:00'),(5,'2012-04-01 00:00:00'),(6,'2012-05-01 12:00:00'),(7,'2012-06-01 00:00:00'), (8,'2012-07-01 00:00:00'); 
UNLOCK TABLES; 

SQLFiddle:

CREATE TABLE `data` (
    `ID` int(11) NOT NULL AUTO_INCREMENT, 
    `DataDateTime` datetime DEFAULT NULL, 
    `Value` int(11) DEFAULT NULL, 
    PRIMARY KEY (`ID`) 
); 

INSERT INTO `data` (`DataDateTime`, `Value`) VALUES 
('2012-02-01 00:00:00',1), 
('2012-03-01 01:00:00',2), 
('2012-04-01 02:00:00',3), 
('2012-05-01 03:00:00',4), 
('2012-06-01 04:00:00',5), 
('2012-07-01 05:00:00',6), 
('2012-08-01 06:00:00',7), 
('2012-09-01 07:00:00',8); 


CREATE TABLE `t` (
    `ID` int(11) NOT NULL AUTO_INCREMENT, 
    `TDateTime` datetime DEFAULT NULL, 
    PRIMARY KEY (`ID`) 
); 

INSERT INTO `t` (`TDateTime`) VALUES 
('2012-01-01 00:00:00'), 
('2012-02-01 00:00:00'), 
('2012-02-01 12:00:00'), 
('2012-03-01 00:00:00'), 
('2012-04-01 00:00:00'), 
('2012-05-01 12:00:00'), 
('2012-06-01 00:00:00'), 
('2012-07-01 00:00:00'); 

マイ所望の出力:

T.ID, T.TDateTime, Data.DataDateTime, Data.Value 
1, 2012-01-01 00:00:00, 2012-02-01 00:00:00, 1 
2, 2012-02-01 00:00:00, 2012-02-01 00:00:00, 1 
3, 2012-02-01 12:00:00, 2012-02-01 00:00:00, 1 
4, 2012-03-01 00:00:00, 2012-02-01 00:00:00, 1 
5, 2012-04-01 00:00:00, 2012-03-01 01:00:00, 2 
6, 2012-05-01 12:00:00, 2012-05-01 03:00:00, 4 
7, 2012-06-01 00:00:00, 2012-05-01 03:00:00, 4 
8, 2012-07-01 00:00:00, 2012-06-01 04:00:00, 5 
+0

OUTERは/ CROSSを適用します限りSQL標準の一部ではありません私が知っているように(間違っていれば私を修正する)。これは、M $ SQLサーバー固有の機能です。これは、ベンダーのロックインの典型的な症状です。あなたが解決策を見つけることを願っています。 – Namphibian

+0

はい、私は知っています!うまくいけば別の方法があります。これが別の方法(JOINなど)を使用して達成できる場合は、私はすべての耳です。 – Simon

+0

上記の 'T'と 'E'のスキーマを含めるか、sqlfiddleのリンクを上記の例と共有することができます – kasi

答えて

1

あなたは、SQL Serverのクエリで、その後(相当)に基づいて、すべてのt行のdata行をランク付け、tdataに参加ORDER BYを渡る​​ことができました。

DATEDIFF(ss, dt1, dt2)の部分はUNIX_TIMESTAMP(dt2) - UNIX_TIMESTAMP(dt1)に置き換えることができました。ランキングは変数を使用して実装できます。ソリューションの試行は次のとおりです。

SELECT 
    ID, 
    TDateTime, 
    DataDateTime, 
    Value 
FROM (
    SELECT 
    ID, 
    TDateTime, 
    DataDateTime, 
    Value, 
    @rnk := @rnk * (@lastid = ID) + 1 AS rnk, 
    @lastid := ID 
    FROM (
    SELECT 
     t.ID, 
     t.TDateTime, 
     data.DataDateTime, 
     data.Value 
    FROM 
     t CROSS JOIN data, 
     (SELECT @lastid := 0, @rnk := 0) s 
    ORDER BY 
     t.ID, 
     (t.TDateTime >= data.DataDateTime) DESC, 
     ABS(UNIX_TIMESTAMP(t.TDateTime) - UNIX_TIMESTAMP(data.DataDateTime)) 
) s 
) s 
WHERE 
    rnk = 1 
; 

デモat SQL Fiddleを見つけることができます。ここで

+0

ありがとうございます。このソリューションはうまくいきます。 – Simon

2

は私の投稿です:)

select *, if(Segment1Time<=ifnull(Segment2Time,Segment1Time), 
      Segment1Value, 
      Segment2Value) Value 
from 
(
    select *, 
    (select DataDateTime from `data` where DataDateTime<=t.TDateTime order by DataDateTime desc limit 1) Segment1Time, 
    (select Value from `data` where DataDateTime<=t.TDateTime order by DataDateTime desc limit 1) Segment1Value, 
    (select DataDateTime from `data` where DataDateTime> t.TDateTime order by DataDateTime limit 1) Segment2Time, 
    (select Value from `data` where DataDateTime> t.TDateTime order by DataDateTime limit 1) Segment2Value 
    from `t` t 
) X 
order by tdatetime; 

そしてここでは、クエリのEXPLAINです。このクエリの良い点は、インデックスがdata.datadatetimeの場合、4つのサブクエリすべてがすべてのレコードを調べてランク付けする必要がなく、すべてが1つのSEEKを生成するということです。理論的には、テーブルが大きくなるほど、より良い結果が得られるでしょう。data

ID SELECT_TYPE TABLE TYPE POSSIBLE_KEYS KEY KEY_LEN REF ROWS EXTRA 
1 PRIMARY <derived2> ALL (null) (null) (null) (null) 8 Using filesort 
2 DERIVED t ALL (null) (null) (null) (null) 8 
6 DEPENDENT SUBQUERY data ALL DataDateTime (null) (null) (null) 8 Using where; Using filesort 
5 DEPENDENT SUBQUERY data index DataDateTime DataDateTime 9 (null) 1 Using where; Using index 
4 DEPENDENT SUBQUERY data ALL DataDateTime (null) (null) (null) 8 Using where; Using filesort 
3 DEPENDENT SUBQUERY data index DataDateTime DataDateTime 9 (null) 1 Using where; Using index 
+0

+1ありがとうございました(>と<記号)をいくつか変更しましたが、これはC# – Simon

+0

から素早く簡単に呼び出すことができるという利点があります。訂正してくれてありがとう。 – RichardTheKiwi

2

要件を理解するのにしばらく時間がかかりました。最後に適用OUTERを使用して基本クエリを分析し始め、この中にそれを変更:

SELECT t.*, data.* 
    FROM t 
    JOIN (SELECT t_ID = t.ID, 
     data_ID = ISNULL((SELECT TOP 1 ID FROM data WHERE data.DataDateTime <= t.TDateTime ORDER BY DataDateTime DESC), 
         (SELECT TOP 1 ID FROM data WHERE data.DataDateTime > t.TDateTime ORDER BY DataDateTime ASC)) 
    FROM t) lnk 
    ON lnk.t_ID = t.ID 
    JOIN data 
    ON data.ID = lnk.data_ID 
    ORDER BY t.ID 

実行計画がが少なく、効率的なとしてそれを示して、一種の私を驚かせています。しかし、DataDateTimeにインデックスを追加すると、それがMSSQLバージョンで便利になるかもしれない何かを劇的に変えましたか?とにかく

、ここから始まる私は、MySQLでこれを作成しました:

SELECT t.*, data.* 
    FROM t 
    JOIN (SELECT t.ID t_ID, 
      COALESCE((SELECT ID FROM data WHERE data.DataDateTime <= t.TDateTime ORDER BY DataDateTime DESC LIMIT 1), 
          (SELECT ID FROM data WHERE data.DataDateTime > t.TDateTime ORDER BY DataDateTime ASC LIMIT 1)) data_ID 
    FROM t) lnk 
    ON lnk.t_ID = t.ID 
    JOIN data 
    ON data.ID = lnk.data_ID 
    ORDER BY t.ID 

は、行うことに期待何やっているようだ...

+0

+1 RichardTheKiwiさんのように、この見た目は正解です:) – Simon

+0

私は私の中でdatediffを見逃していたことに気づきましたが、簡単に追加できました。サブクエリ全体に対してここで合体して表現された2つのセグメントの間の依存関係によって、より困難になります。 – RichardTheKiwi

+0

完全に正直なところ、私はまだ/ original/queryを取得しているとは確信していないので、追加のDateDiff()が必要かどうかわかりません。私は単に、記述と予想される出力に基づいてニーズを把握しようとしました。 – deroby

関連する問題