0

存在する場合、特定の最新の MainNumber、Serial、BarType、および Notes を取得したいと考えてMainNumberいます。BarType はルックアップ テーブルに格納され、BarID で参照されることに注意してください。

不合理はこれを思いついた:

SELECT @MainNumber, COALESCE(n.Notes, 'None')
FROM numbers 
     LEFT JOIN notes n ON numbers.MainNumber = n.MainNumber
     LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date
WHERE n2.Date IS NULL AND numbers.MainNumber = @MainNumber

これは Notes であるかどうかNULLに関係なく問題ありませんが、Serial と BarType が必要です。MainNumber は、その存続期間中に複数のシリアルに割り当てられている可能性がありますが、最新のシリアルのみが必要です。(他のテーブルの約15の他のフィールドでこれを行う必要があるため、可能な場合はパフォーマンスの高い回答をいただければ幸いです)

テーブル

数字の表:

CREATE TABLE `numbers` (
  `ID` int(10) unsigned NOT NULL auto_increment,
  `MainNumber` varchar(11) NOT NULL,
  `Serial` varchar(20) NOT NULL,
  `Date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`ID`),
  UNIQUE KEY `Serial` (`Serial`)
) ENGINE=MyISAM AUTO_INCREMENT=460 DEFAULT CHARSET=latin1

備考表:

CREATE TABLE `notes` (
  `ID` int(10) unsigned NOT NULL auto_increment,
  `MainNumber` varchar(11) NOT NULL,
  `Notes` longtext NOT NULL,
  `Date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`ID`),
  KEY `MainNumber` (`MainNumber`)
) ENGINE=MyISAM AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC

ref_bars テーブル:

CREATE TABLE `ref_bars` (
  `BarID` varchar(6) NOT NULL,
  `BarType` varchar(30) NOT NULL,
  PRIMARY KEY  USING BTREE (`BarID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

バーテーブル:

CREATE TABLE `bars` (
  `ID` int(10) unsigned NOT NULL auto_increment,
  `MainNumber` varchar(11) NOT NULL,
  `BarID` varchar(6) NOT NULL,
  `Date` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  PRIMARY KEY  (`ID`),
  KEY `MainNumber` (`MainNumber`)
) ENGINE=MyISAM AUTO_INCREMENT=212 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC

サンプルデータ

SELECT * FROM notes:

'ID','MainNumber','Notes','Date'
'1','1','repaired','2009-03-23 12:00:00'
'2','1','replaced','2009-08-15 19:20:05'

注: MainNumber = 1 の場合は 2 行ありますが、MainNumber が 2 の場合は行はありません。ID は技術的なものであり、使用されることはありません。

SELECT * FROM numbers:

'ID','MainNumber','Serial','Date'
'1','1','4642785154854','2008-08-15 12:30:00'
'2','1','4642315642316','2009-08-15 12:50:00'
'3','2','5412558456223','2010-08-15 11:30:00'

SELECT * FROM bars:

'ID','MainNumber','BarID','Date'
'1','1',1,'2008-08-15 12:30:00'
'2','1',2,'2009-08-15 12:50:00'
'3','2',2,'2010-08-15 11:30:00'

SELECT * FROM ref_bars:

'BarID','BarType'
'1','Banned'
'2','Payment required'

期待される出力

メイン番号 = 1

MainNumber,Notes,Banned,Unpaid
'1','replaced','Yes','Yes'

メイン番号 = 2

MainNumber,Notes,Banned,Unpaid
'2','None','No','Yes'

編集:物事をより明確にしながら、それを修正してテストしました(うまくいけば)。私は今日、他のことをするために急がされました。書き方が悪く、不完全な質問で人々の時間を無駄にしてしまい申し訳ありません。

より複雑な要件を明確にするために更新

4

5 に答える 5

1

Unreasonが提案するように、JOINを使用してそれを行うことができます。

別の方法は、サブクエリを使用することです。

select distinct s.MainNumber, 
COALESCE(
  (select n.notes from notes n where n.MainNumber=s.MainNumber order by n.Date desc limit 1), 
  'None') as LastNote
from numbers s
WHERE s.MainNumber=?

JOINを使用したソリューションは、パフォーマンスが向上する場合とそうでない場合があることに注意してください。試してみる必要があります。

また、「LIMIT」はMySQL固有(ANSI SQLではない)であるため、別のDBMSに移行する場合は注意が必要です。

于 2010-10-11T15:42:52.203 に答える
1

問題を再現しないため、最初のクエリを無視することを選択すると、期待される出力が表示されます。次のことを達成しようとしていると思います。

テーブルMainNumber内のレコードを検索し、notes最大日付の行を返します。特定のテーブル ノートにレコードがない場合は、 MainNumber定数を返し ます。'None'

(これは要求されたものではない可能性があります。そうでない場合は、期待される出力を修正してください)

これは、たとえば次のようにして簡単に実現できます。

SELECT @MainNumber, n.Notes
FROM notes n
     LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date
WHERE n2.Date IS NULL AND n.MainNumber = @MainNumber

メモから最新の行を返します。アプリケーション側から行が返されない場合は、 @MainNumber, 'None' を出力するだけです...

純粋な SQL を探している場合 (および数値テーブルの他の列が必要であると仮定した場合)、次のことができます。

SELECT @MainNumber, COALESCE(n.Notes, 'None')
FROM numbers 
     LEFT JOIN notes n ON numbers.MainNumber = n.MainNumber
     LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date
WHERE n2.Date IS NULL AND numbers.MainNumber = @MainNumber

編集: 最初のクエリがテストされます

mysql> SET @MainNumber = 1;                                                     Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @MainNumber, n.Notes FROM notes n      LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date WHERE n2.Date IS NULL AND n.MainNumber = @MainNumber;
+-------------+----------+
| @MainNumber | Notes    |
+-------------+----------+
|           1 | replaced | 
+-------------+----------+
1 row in set (0.00 sec)

数値テーブルに複数のエントリがある場合、2 番目のクエリは最初に複数の行を返しましたが、DISTINCT はそれを修正します。

mysql> SET @MainNumber = 1;                                                     Query OK, 0 rows affected (0.00 sec)

mysql> SELECT DISTINCT @MainNumber, COALESCE(n.Notes, 'None')
    -> FROM numbers 
    ->      LEFT JOIN notes n ON numbers.MainNumber = n.MainNumber
    ->      LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date
    -> WHERE n2.Date IS NULL AND numbers.MainNumber = @MainNumber
    -> ;
+-------------+---------------------------+
| @MainNumber | COALESCE(n.Notes, 'None') |
+-------------+---------------------------+
|           1 | replaced                  | 
+-------------+---------------------------+
1 row in set (0.00 sec)

mysql> SET @MainNumber = 2;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT DISTINCT @MainNumber, COALESCE(n.Notes, 'None')
    -> FROM numbers 
    ->      LEFT JOIN notes n ON numbers.MainNumber = n.MainNumber
    ->      LEFT JOIN notes n2 ON n.MainNumber = n2.MainNumber AND n.Date < n2.Date
    -> WHERE n2.Date IS NULL AND numbers.MainNumber = @MainNumber
    -> ;
+-------------+---------------------------+
| @MainNumber | COALESCE(n.Notes, 'None') |
+-------------+---------------------------+
|           2 | None                      | 
+-------------+---------------------------+
1 row in set (0.00 sec)
于 2010-10-11T15:21:40.443 に答える
0
SELECT MainNumber,
       COALESCE(Notes,"None") as Notes,
       if(BarID=1,"Yes","No") as Banned,
       if(BarID=2,"Yes","No") as Unpaid,
       COALESCE(notes.Date,CURRENT_TIMESTAMP) as Date
FROM numbers LEFT JOIN notes USING (MainNumber)
     LEFT JOIN bars USING (MainNumber)
GROUP BY MainNumber,Date
HAVING Date=COALESCE(MAX(notes.Date),CURRENT_TIMESTAMP)
于 2010-10-14T06:57:43.953 に答える
0

私はついにそれを解決しました。実際には、私が思っていたよりもはるかに単純です。私が書いていた元のクエリにも近いです。

SELECT
    s.MainNumber,
    n.Notes
FROM numbers s
JOIN (
    SELECT
        MAX(Date) AS Date,
        MainNumber
    FROM numbers
    WHERE MainNumber = 2
) AS sx
    ON s.MainNumber = sx.MainNumber AND s.Date = sx.Date

LEFT JOIN notes n
    ON s.MainNumber = n.MainNumber
LEFT JOIN (
    SELECT
            MAX(Date) AS Date,
            COALESCE(MainNumber,0) AS MainNumber
    FROM notes
    WHERE MainNumber = 2
) AS nx
    ON n.MainNumber = nx.MainNumber AND n.Date = nx.Date
于 2010-10-14T11:41:13.303 に答える
0

たぶん、このようなものですか?

LEFT JOIN (select notes n
JOIN (
    SELECT
        MAX(Date) AS Date,
        MainNumber
    FROM notes
    GROUP BY MainNumber
) AS nx
    ON n.MainNumber = nx.MainNumber AND n.Date = nx.Date) n
ON notes.MainNumber = main.MainNumber

なぜあなたがそれを持っているのかを説明していないので、where句を削除しました。必要な場合は、もう一度挿入するだけです。

編集:クエリは更新されますが、必要なものを正確に理解することはまだ困難です。サンプル データを書いたとき、期待される出力と共に各テーブルに 2 ~ 3 行を意味していました。それが役に立てば幸い。

于 2010-10-11T10:09:32.460 に答える