【问题标题】:SQL Options Storage and ReferenceSQL 选项存储和引用
【发布时间】:2012-02-03 22:22:53
【问题描述】:

如果我有一张桌子:

CREATE TABLE Kids (
    kid_id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    kid_name varchar(45) NOT NULL,
    kid_favcolors (text) NULL,
    PRIMARY_KEY(kid_id)
    )

我有一张桌子:

CREATE TABLE Colors (
    color_id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    color_name varchar(45) NOT NULL,
    PRIMARY_KEY(color_id)
)

通过逗号分隔的 ID 引用喜欢的颜色的行:

INSERT INTO Kids(kid_name, kid_favcolors) VALUES('Joe','1,2,3,4,5');
INSERT INTO Kids(kid_name, kid_favcolors) VALUES('Mary','1,2,3');

我将如何创建一个语句,该语句将返回 Kid 数据库中的每个条目以及 Kid_favcolors 列中引用的所有 ID 的 Kid_name 和 color_name。

例如:

COLORS:
color_id 颜色名称 1 黄色 2 绿色 3 蓝色 4紫 5红色 6棕色 7 黑色
KIDS:
Kid_id 孩子名字 Kid_favcolors 1 乔 1,2,3,4,5 2 玛丽 1,2,3

我想找回

child_id 孩子名字 favorite_colors 1乔黄、绿、蓝、紫、红 2 玛丽黄、绿、蓝

正在对现有数据和数据库结构执行查询。如果没有可行的解决方案,重新排列数据结构是可能的,但我认为会为解决方案增加大量时间。无论哪种方式,都需要一些帮助。

我可以使用以下方法从数据库中检索颜色:

SELECT STUFF((SELECT ', ' + color_name FROM colors WHERE color_id IN (1,2,3,4,5) FOR XML PATH('')),1, 2, '') AS colors

        colors
1       yellow, green, blue, purple, red

但是当我尝试更复杂的查询时,我似乎无法通过从 Kids 表中提取 id 来找到合并上述语句的方法。

SELECT kids.kid_id, kids.kid_name, favorite_colors FROM kids JOIN colors ON colors.id IN kids.kid_favcolors as favorite_colors

虽然它看起来对我有用,但不起作用。不知道我是远了还是真的很近。

【问题讨论】:

  • 我会说你的设计在这种情况下是不正确的,如果有第三个表有 child_id 和 color_id 不是更好,这样你就可以只选择 color_id 的 child_id = x...
  • 与更传统的多对多表相比,您更喜欢通过逗号分隔的 id 引用最喜欢的颜色,这是有原因的吗?
  • 就像我说的,这是一个现有的基础设施。上面显示的数据是使用我能想到的第一个场景的娱乐。这个想法是尝试在不重组他们的数据库以及读取和修改它的所有脚本的情况下实施修复。如果这条路线没有解决方案,我将编写一个脚本,将逗号分隔的 id 转换为多对多表,并重写它们的所有管理脚本。
  • 如果您使用的是最新版本的 MySQL(或更好的 PostgreSQL),您可以使用多对多重新设计数据库并创建一个显示旧结构的视图。然后你只需要改变他们的脚本来引用视图的名字而不是表的名字,为你节省了大量的重写工作。

标签: mysql database database-design data-structures


【解决方案1】:

在原始解决方案中,将 CSV 字符串存储在字段中违反了 1NF;实际上——根据定义——该表甚至不符合关系。因此,在这种情况下,将字符串视为原子数据,并在应用程序层对其进行分解。

要在 DB 层解决它,只需修复设计即可。

【讨论】:

  • 虽然我同意你的数据规范化,但目前的情况仍然存在,归结为时间/费用问题。如果我重新设计数据库以更好地组织数据,那么我必须通过并编辑多个脚本,这些脚本以当前格式引用数据,这将导致比 SQL 语句更多的工作。
【解决方案2】:

我已经想出了一个解决方案;虽然它不漂亮,但它有效。

SELECT 
  kid_id,
  kid_name, 
  (SELECT STUFF(
     (SELECT ', '+color_name FROM colors WHERE color_id in 
        (SELECT s from SplitString(kid_favcolors,',')) 
     FOR XML PATH(''))
   ,1,2,'')) AS favorite_colors 
FROM KIDS
child_id 孩子名字 favorite_colors 1乔黄、绿、蓝、紫、红 2 玛丽黄、绿、蓝

我已与他们讨论过重新设计数据库并实施当前管理站点以适应更改

我使用的拆分字符串函数:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create function [dbo].[SplitString] 
(
    @str nvarchar(4000), 
    @separator char(1)
)
returns table
AS
return (
    with tokens(p, a, b) AS (
        select 
            1, 
            1, 
            charindex(@separator, @str)
        union all
        select
            p + 1, 
            b + 1, 
            charindex(@separator, @str, b + 1)
        from tokens
        where b > 0
    )
    select
        p-1 zeroBasedOccurance,
        substring(
            @str, 
            a, 
            case when b > 0 then b-a ELSE 4000 end) 
        AS s
    from tokens
  )

【讨论】:

    猜你喜欢
    • 2012-12-31
    • 1970-01-01
    • 1970-01-01
    • 2014-03-05
    • 2017-05-22
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    • 2017-10-13
    相关资源
    最近更新 更多