【问题标题】:SQL Server - Trying to de-normalize my tableSQL Server - 试图去规范化我的表
【发布时间】:2017-08-28 13:20:47
【问题描述】:

为标题道歉,但我正在尝试做一些超出我水平的事情,即使是为了我解释它。

假设我有一张包含变量 person、foodstuff 和 amount 的表格:

 Person  food     Amount
 Mike    Butter   3
 Mike    Milk     4
 Mike    Chicken  2
 Tim     Milk     4
 John    Chicken  2

通过在查询中将表与自身连接起来,我设法制作了一个列表,其中食物是新变量的基础,值是数量。上表将变为:

Person  Butter Milk Chicken
Mike    3      4    2

代码大概是:

Select 
    a.person, 
    b.amount as Butter,
    c.amount as Milk, 
    d.amount as Chicken
from PersonFoodAmount a
inner join PersonFoodAmount b on a.person = b.person
inner join PersonFoodAmount c on a.person=c.person
where b.food='Butter' 
and c.food='Milk'
and d.food='Chicken'

现在,这给了我迈克,因为他勾选了所有选项。但我还需要部分匹配:

Person  Butter Milk Chicken
Mike    3      4    2
Tim     NULL   4    NULL
John    NULL   Null 2

我尝试了各种联接,包括完全外部联接,但我仍然只得到冰箱满的人。

有什么建议吗?

【问题讨论】:

  • 你需要使用sql pivot...

标签: sql sql-server join


【解决方案1】:

您可以使用 Pivot 来制作它。

DECLARE @PersonStuff TABLE (Person varchar(10), Food varchar(10), Amount INT)

INSERT INTO @PersonStuff VALUES
('Mike','Butter', 3),
('Mike','Milk', 4),
('Mike','Chicken', 2),
('Tim','Milk', 4),
('John','Chicken', 2)

SELECT 
    * 
FROM ( 
    SELECT 
        * 
    FROM @PersonStuff ) AS SourceTable
PIVOT ( 
    AVG(Amount) 
    FOR Food IN ( [Butter],[Milk],[Chicken] ) 
) AS PivotTable

结果:

Person  Butter  Milk    Chicken
John    NULL    NULL    2
Mike    3       4       2
Tim     NULL    4       NULL

【讨论】:

  • 这似乎是要走的路,谢谢。但更复杂的是,“牛奶”实际上是属于“牛奶”类别的几个数字。我正在尝试使用“forsurvey_detail_id in ([('184','202','235','253','325','359','377') as tilfreds]”代替“FOR食物输入([黄油]”但我得到一个:“不正确的值“('184','202','235','253','325','359','377')作为tilfreds”是在 PIVOT 运算符中提供。”
  • 你应该这样写值([184],[202],[235],[253],[325],[359],[377])
  • 但是我能否将多个数字 AS 重新编码为一个变量 tilfreds (/milk)?看起来你写它的方式我会为每个数字得到一个单独的变量? (“七种不同的食物”)?
  • 你必须这样写。但是如果你有动态变量,那么你需要在这个查询上生成并执行动态 SQL 查询。
【解决方案2】:

我会建议更好的条件聚合:

SELECT t.person,
       MAX(CASE WHEN t.food = 'Butter' THEN t.amout END) as Butter,
       MAX(CASE WHEN t.food = 'Milk' THEN t.amout END) as Milk,
       MAX(CASE WHEN t.food = 'Chicken' THEN t.amout END) as Chicken
FROM PersonFoodAmount t
GROUP BY t.person

这样,您不必将表加入 3 次。另外,我发现这篇文章读一次就更容易理解了。

【讨论】:

  • 操作数数据类型 NULL 对 max 运算符无效。
  • @sagi 为什么或何时会在 PIVOT 上使用您的解决方案?
  • 当它的列数量有限时,它具有常量名称(我记得,它甚至更快)。我总是喜欢这个动作,因为新程序员往往不理解 PIVOT。 @Eli
  • @sagi,您的代码可以正常工作,抱歉。我的测试代码给了我这个错误
  • 我同意后一个原因,因为 PIVOT 对于很少接触的人来说可能很难阅读——尽管关于你给出的第一个原因。除非您使用动态 SQL,否则每当引入新值时,您都需要对查询进行修改。
猜你喜欢
  • 2013-11-21
  • 1970-01-01
  • 1970-01-01
  • 2011-03-31
  • 2017-07-31
  • 2012-12-31
  • 2015-02-21
  • 2018-07-08
  • 1970-01-01
相关资源
最近更新 更多