MySQL根据查找表中的值从多个表中按日期获取最新记录
我想获取给定 MainNumber
的最新 MainNumber、Serial、BarType 和 Notes(如果存在)。请注意,BarType 存储在查找表中并通过 BarID 引用。
Unreason 提出了这个:
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 个其他字段执行此操作,因此如果可能,我们将不胜感激)
表
Numbers 表:
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
Notes 表:
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
bars 表:
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 时没有行。ID 只是技术性的,从未使用过。
从数字中选择*
:
'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'
从条形中选择*
:
'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'
从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'
编辑:修复并测试它,同时使事情变得更清晰(希望如此)。今天早些时候我被赶去做其他事情,很抱歉因为一个写得不好、不完整的问题浪费了人们的时间。
更新以澄清更复杂的要求
I want to get the latest MainNumber, Serial, BarType and Notes for a given MainNumber
, if they exist. Note that BarType is stored in a lookup table and referenced with BarID.
Unreason came up with this:
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
This is fine whether Notes is NULL
or not, but now I need the Serial and the BarType. A MainNumber may have been assigned to multiple Serials during its lifetime, but I only want the latest Serial. (I'll need to do this with about 15 other fields in other tables, so a performant answer would be appreciated where possible)
Tables
Numbers Table:
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
Notes table:
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 table:
CREATE TABLE `ref_bars` (
`BarID` varchar(6) NOT NULL,
`BarType` varchar(30) NOT NULL,
PRIMARY KEY USING BTREE (`BarID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
bars table:
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
Sample Data
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'
Note: two rows for MainNumber = 1, but no row for a MainNumber of 2. The IDs are just technical and are never used.
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'
Expected Output
MainNumber = 1
MainNumber,Notes,Banned,Unpaid
'1','replaced','Yes','Yes'
MainNumber = 2
MainNumber,Notes,Banned,Unpaid
'2','None','No','Yes'
Edit: Fixed it and tested it, whilst making things clearer (hopefully). I was rushed off to do other things earlier today, sorry for wasting people's time with a badly-written, incomplete question.
Updated to clarify the more complex requirements
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以按照 Unreason 的建议使用 JOIN 来完成此操作。
另一种方法是使用子查询:
请注意,使用 JOIN 的解决方案可能会或可能不会执行得更好,您必须尝试一下。
另请注意,“LIMIT”是 MySQL 特定的(不是 ANSI SQL),因此如果您打算迁移到另一个 DBMS,请务必小心。
You can do it with a JOIN, as suggested by Unreason.
Another way would be with a subquery:
Note that the solution using JOIN may or may not perform better, you'll have to try it.
Also note that "LIMIT" is MySQL-specific (not ANSI SQL), so take care if you intend to migrate to another DBMS.
选择忽略您的初始查询,因为它们不会重现您的问题我正在查看您的预期输出我假设您正在尝试实现以下目标:
(这可能不是所要求的,所以如果不是,请更正预期的输出)
这可以很容易地实现,例如
Which will return the最新行 fromnotes.
现在,从应用程序端来看,如果它不返回任何行,只需打印 @MainNumber, 'None' 就可以了...
如果您寻找纯 SQL(并假设您确实需要数字表中的其他一些列),那么您可以做:
编辑:
第一个查询经过测试
第二个查询最初在数字表中有多个条目的情况下返回多行,DISTINCT 修复了该问题
Choosing to ignore your initial queries since they do not reproduce your problem I am looking at you expected output I assume that you are trying to achieve the following:
(this might not be what is requested, so please correct the expected output if it is not)
This can be easily achieved with, for example
Which will return the latest row from notes.
Now from the application side if it does not return any rows just print @MainNumber, 'None' and that is it...
If you look for pure SQL (and assuming that you do need some other columns from the numbers table) then you can do:
EDIT:
The first query is tested
The second query initially returned multiple rows in case of multiple entries in the numbers table, DISTINCT fixes that
也许是这样的?
我删除了 where 子句,因为您没有描述为什么拥有它。如果您需要它,只需再次插入即可。
编辑:查询已更新,但仍然很难准确理解您想要的内容。当我编写示例数据时,我的意思是每个表包含 2-3 行以及预期输出,如果您可以简化示例,那就更好了。希望有帮助。
Maybe something like this?
I removed the where-clause since you don't describe why you have it. If you need it you can just insert it again.
EDIT: The query is updated, but it is still hard to understand exatcly what you want. When I wrote example data I meant 2-3 rows for each table together with expected output, and if you could simplify the example that would be even better. Hope it helps.
我终于解决了。实际上比我想象的要简单得多。它也更接近我编写的原始查询。
I finally worked it out. It's actually a lot more simple than I thought. It's closer to the original query I was writing, too.