在SQL中搜索多个值以获取值与存储在一列中

时间:2012-06-14 23:41:31

标签: sql database-design

我需要在SQL数据库中存储乐透号码。共有8个单独的数字构成了乐透号码。

EX:07-12-34-40-59-80-88-89

我首先考虑将这些数据存储在一行中,其中包含名为lotto1 - lotto8的列。这是有道理的,因为乐透号码总是从低到高显示,用户需要查看存储的乐透号码。写一个select语句是微不足道的。

我还需要看看有多少乐透号码是赢家。为此,我需要在每一列中搜索每个中奖号码。

EX:如果获奖号码是01-02-03-04-05-06-07-08,我需要检查每一栏,看看“07”在我的lotto1栏中。

如果所有乐透号码都存储在1列中,那么检查获胜者会更容易,并且他们有一个LottoTicketID来将8行数据与1张票据相关联。在检查获胜者时,我不需要说明哪些具体的数字/位置是匹配的,只是说有多少匹配。

从LOTTOTABLE中选择LottoTicketID,Count(LottoTicketID) LottoNumber in(01,02,03,04,05,06,07,08) GROUP BY LottoTicketID

以这种方式存储会导致问题,因为我需要编写7个连接才能显示数字。

有人可以建议一种方法来存储这些数据,以便我可以: 1.快速显示乐透号码/ entires 2.检查获奖者

4 个答案:

答案 0 :(得分:3)

你可能想要解决这个问题的方法是有两个表来存储有关彩票的信息:

  • lottery_tickets :存储有关每张彩票的信息:

    lottery_tickets
    ----------------------
    id [PK]
    first_name
    last_name
    date_given
    ...
    
  • lottery_ticket_numbers :存储相应的彩票号码:

    lottery_ticket_numbers
    ----------------------
    id        [PK](FK)
    number    [PK]
    position  
    

通过1:N识别关系连接id字段上的两个,并让每个彩票在lottery_ticket_numbers表中有8个对应的行。 position字段将跟踪整个数字字符串中每个数字的位置(1-8)。

这将允许您做的是通过将表格加在一起并将其缩小到哪些彩票所有匹配的数字来轻松找出中奖彩票:

SELECT
    a.*,
    GROUP_CONCAT(b.number ORDER BY position SEPARATOR '-') AS lottery_number
FROM
    lottery_tickets a
INNER JOIN
    lottery_ticket_numbers b ON a.id = b.id
WHERE
    b.number IN (07,12,34,40,59,80,88,89)
GROUP BY 
    a.id
HAVING 
    COUNT(b.number) = 8

结果集看起来像这样:

id   |   first_name   |   last_name   |   date_given   |   lottery_number
--------------------------------------------------------------------------------
823  |   Zane         |   Bien        |   2012-01-01   |   34-80-07-89-12-40-59-88
2321 |   Jeff         |   Clark       |   2012-01-14   |   59-07-88-40-12-34-80-89

注意

  • 如果您使用的是MySQL,GROUP_CONCAT()功能会以XX-XX-XX-XX-XX-XX-XX-XX格式合并中奖彩票号码,并按照原始顺序编号它。如果你没有使用MySQL,我不确定其他DBMS中是否存在类似的功能。

现在您可能还想存储有关实际中奖彩票号码的数据。为此,您以相同的方式使用两个表:一个用于抽奖号码,另一个用于相应的号码:

  • <强> winning_numbers

    winning_numbers
    ----------------------
    id [PK]
    date_pulled
    
  • <强> winning_numbers_numbers

    winning_numbers_numbers
    ----------------------
    id     [PK](FK)
    number [PK]
    

查询中奖彩票:

SELECT
    a.*,
    GROUP_CONCAT(b.number ORDER BY position SEPARATOR '-') AS lottery_number
FROM
    lottery_tickets a
INNER JOIN
    lottery_ticket_numbers b ON a.id = b.id
WHERE
    b.number IN
    (
        SELECT number
        FROM winning_numbers_numbers
        WHERE id = <id of a particular lottery number>
    )
GROUP BY 
    a.id
HAVING 
    COUNT(b.number) = 8

与上一个查询几乎相同,但现在数字列表是子查询的结果集。

显示中奖彩票号码很简单。例如:

检索所有中奖号码及其提取日期;以升序显示数字字符串作为数字,并按最近提取的数字排序:

SELECT
    GROUP_CONCAT(b.number ORDER BY b.number SEPARATOR '-') AS winning_number,
    a.date_pulled
FROM
    winning_numbers a
INNER JOIN
    winning_numbers_numbers b ON a.id = b.id
GROUP BY 
    a.id
ORDER BY
    a.date_pulled DESC

请注意,当您插入中奖号码时,您不必担心所插入号码的顺序。由于它们始终按升序显示,ORDER BY中的GROUP_CONCAT()会为您处理。{/ p>


现在让我们来看看如果你使用基于列的方法你必须做什么(将中奖号码和票号作为单行存储,但每个号码有8列):

假设架构:

winning_numbers(id, date_pulled, n1, n2, n3, n4, n5, n6, n7, n8)

ticket_numbers(id, fname, lname, date_given, n1, n2, n3, n4, n5, n6, n7, n8)

查找给定彩票号码的所有中奖彩票

SELECT
    a.*
FROM 
    ticket_numbers a
INNER JOIN
    winning_numbers b ON
        a.n1 IN (b.n1, b.n2, b.n3, b.n4, b.n5, b.n6, b.n7, b.n8) AND
        a.n2 IN (b.n1, b.n2, b.n3, b.n4, b.n5, b.n6, b.n7, b.n8) AND
        a.n3 IN (b.n1, b.n2, b.n3, b.n4, b.n5, b.n6, b.n7, b.n8) AND
        a.n4 IN (b.n1, b.n2, b.n3, b.n4, b.n5, b.n6, b.n7, b.n8) AND
        a.n5 IN (b.n1, b.n2, b.n3, b.n4, b.n5, b.n6, b.n7, b.n8) AND
        a.n6 IN (b.n1, b.n2, b.n3, b.n4, b.n5, b.n6, b.n7, b.n8) AND
        a.n7 IN (b.n1, b.n2, b.n3, b.n4, b.n5, b.n6, b.n7, b.n8) AND
        a.n8 IN (b.n1, b.n2, b.n3, b.n4, b.n5, b.n6, b.n7, b.n8) AND
        b.id = <winning number id>

如果你问我的话,那就是很多IN的问题...... !!!

这种方法的优点是您不需要特定于MySQL的GROUP_CONCAT函数来显示票号。

答案 1 :(得分:1)

  

以这种方式存储会导致问题,因为我需要编写7个连接才能显示数字。

如果您需要在一行中显示所有数字,那么您需要进行7次连接的唯一时间。如果您在数据库外部处理这些(或者甚至使用存储过程),将它们收集成可读格式是微不足道的。

如果您的数据库支持,您可能拥有的另一个选项是将所有数字放在单个数组类型的列中或使用某种多行分析函数。您可以随时写一个视图来解决问题。

答案 2 :(得分:1)

为什么需要编写7个连接来显示数字?你可以这样写:

SELECT LottoNumber FROM LOTTOTABLE
WHERE LottoTicketID=n
ORDER BY LottoNumber

您可以使用您建议的查询来检查它们:

SELECT LottoTicketID, Count(LottoTicketID) 
FROM LOTTOTABLE 
WHERE LottoNumber in (01,02,03,04,05,06,07,08) 
GROUP BY LottoTicketID

您还可以使用以下方法将此列表限制为获胜者:

HAVING Count(LottoTicketID) = 8

您还可以将乐透号码存储为TINYINT以保持数据库大小不变。

答案 3 :(得分:0)

如您所述,将数字存储在一列中有很多优点。如果唯一剩下的问题是将它们组合在一起的复杂性,那么干净利落地做这件事有很多可能性 - 而且经常被忽视,所以经常会问这个问题。

这里处理得很好,有几种SQL风格,以及一些独立于平台的选项: Concatenate many rows into a single text string?