Я хочу получить последние 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, но мне нужен только последний Serial. (Мне нужно будет сделать это примерно с 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, но не строка для MainNumber из 2. Идентификаторы являются только техническими и никогда не используются.
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'
Ожидаемый результат
MainNumber = 1
MainNumber,Notes,Banned,Unpaid
'1','replaced','Yes','Yes'
MainNumber = 2
MainNumber,Notes,Banned,Unpaid
'2','None','No','Yes'
Изменить: Исправлено и протестировано, в то время как все стало проще (надеюсь). Сегодня меня бросились на другие дела, извините за то, что тратили людей на плохо написанный, неполный вопрос.
Обновлено для уточнения более сложных требований
Я, наконец, решил. На самом деле это намного проще, чем я думал. Это ближе к исходному запросу, который я тоже писал.
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
Вы можете сделать это с помощью JOIN, как это было предложено Unreason.
Другой способ: с подзапросом:
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), поэтому будьте осторожны, если вы планируете перейти на другую СУБД.
Выбор игнорировать ваши начальные запросы, так как они не воспроизводят вашу проблему. Я рассматриваю ожидаемый результат. Предполагаю, что вы пытаетесь достичь следующего:
С учетом
MainNumber
найдите запись в tabelnotes
и верните строку с максимальной датой, если нет записей в табличных заметках для данного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
EDIT: Первый запрос проверен
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)
Второй запрос первоначально возвратил несколько строк в случае нескольких записей в таблице чисел, 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)
SET @MainNumber = 1;
запрос SET @MainNumber = 1;
, но тогда я не получаю результат. Я пробовал также с 2
, '1'
и '2'
. Также мне нужно получить MainNumber из numbers
как при notes
MainNumber = 2 в notes
не будет строк. Я снова обновлю вопрос.
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)
LEFT JOIN
к барам и добавив notes.Date к предложению SELECT
), но затем он не дал результатов. Не могли бы вы немного поработать над этим?
Может быть, что-то вроде этого?
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-clause, так как вы не описали, почему у вас это есть. Если вам это нужно, вы можете просто вставить его снова.
EDIT: Запрос обновляется, но по-прежнему сложно понять, что вы хотите. Когда я писал данные примера, я имел в виду 2-3 строки для каждой таблицы вместе с ожидаемым выходом, и если бы вы могли упростить пример, который был бы еще лучше. Надеюсь, что это поможет.