如何在SQL Server中将两个查询的结果合并?

6
这是我今天的第二个SQL问题 - 我在DBA方面有点新手...
我正在尝试将一个复杂的SQL查询连接起来,将大约12张表中的数据合并成一张表。虽然数据库中存在一对多的关系,但我知道每个关系的最大数量。
因此,我已经(在stack overflow的帮助下!)展开了我的数据库的第一层,并拥有一对查询,现在必须将它们连接在一起:
(节选)
SELECT 
  A.StudentId, C1.Topic AS SIoC1, C1.Level AS SIoCScore1
FROM Assessment A
  LEFT JOIN Concern C1 ON A.Id = Assessment_Id and C1.TopicNumber = 1
WHERE A.Type = 'School'

SELECT 
  A.StudentId, C1.Topic AS PIoC1, C1.Level AS PIoCScore1
FROM Assessment A
  LEFT JOIN Concern C1 ON A.Id = Assessment_Id and C1.TopicNumber = 1
WHERE A.Type = 'Parent'

是否可以给查询命名别名?
或者我该怎么样将这两个查询连接起来,使输出结果像这样:

| A.Id | SIoC1 | SIoCScore1 | PIoC1 | PIoCScore1 |

**更新** 这个问题的背后是进行评估,学校和家长都必须报告。因此,单行标识具有学校和家长值的评估。

我正在使用SQL Server 2005。

谢谢!

*进一步更新* 这个查询似乎可以完成任务...

SELECT PreConcerns.StudentId, TIoC1, TIoCScore1, PIoC1, PIoCScore1 
FROM
  Assessment PreConcerns
  LEFT OUTER JOIN
  (
    SELECT 
      P.StudentId, C1.Topic AS TIoC1, C1.Level AS TIoCScore1
    FROM Assessment  P
      LEFT JOIN Concern C1 ON P.Id = C1.Assessment_Id and C1.TopicNumber = 1
    WHERE P.Type = 'School'
  ) scons
  ON scons.StudentId= PreConcerns.StudentId
  LEFT OUTER JOIN
  (
    SELECT 
      P.StudentId, C1.Topic AS PIoC1, C1.Level AS PIoCScore1
    FROM Assessment  P
      LEFT JOIN Concern C1 ON P.Id = C1.Assessment_Id and C1.TopicNumber = 1
    WHERE P.Type = 'Parent'
  ) pcons
ON pcons.StudentId = PreConcerns.StudentId

进一步更新(第二次!)** (我不确定是否应该将其作为一个新问题重新打开?!) 今天回到工作岗位,发现我上面的“解决方案”并没有完全解决问题 - 它会为每个评估创建两行。

因此,简要回顾一下,我有以下表格:

Student (int:id, varchar(50):name)
Assessment (int:id, date:date, int:StudentId, )
Concern (int:id, int:assessment_id, varchar(20):topic, int:level)

对于系统中的每个学生,都会有两个评估——一个类型为“学校”,一个类型为“家长”。

我想创建一行将评估和关注点结合起来:

(伪列:)

| Assessment.StudentId | SchoolConcernTopic | SchoolConcernLevel | ParentConcernTopic | ParentConcernLevel |

或从上面的SQL语句中:

| PreConcerns.StudentId | SIoC1 | SIoCScore1 | PIoC1 | PIoCScore1 |

只有每个学生填写一行,结合两次评估。 使用上述SQL语句可以实现此结构,但是会返回两行!我无法确定如何更新它以仅返回一行-非常感谢您的帮助!!

一如既往地感谢!

8个回答

4

这可以通过一条查询语句完成。IN子句只是一种花哨的说法,即A.Type = 'School' OR A.Type = 'Parent'

SELECT 
  A.Id, C1.Topic AS PIoC1, C1.Level AS PIoCScore1
FROM Assessment A
  LEFT JOIN Concern C1 ON A.Id = Assessment_Id and C1.TopicNumber = 1
WHERE A.Type IN ('School','Parent')

不幸的是,这并没有使学校和家长的分数保持在同一行 - 谢谢回复。 - laura
@lainie:你的表中哪些字段用于将“学校”类型的结果与“家长”相关联? - Tony
@Joe:你完全正确——这是一个将学校和家长联系起来的学生ID。抱歉——混淆效果太好了...... - laura
@lainie:根据您的编辑,看起来您已经找到了解决方案,还是需要额外的帮助? - Joe Stefanelli
谢谢,我认为我的解决方案很好 - 只是非常笨重!感谢您的所有帮助! - laura
显示剩余3条评论

2
请确保你想要的字段名在第一个查询中指定,然后使用UNION ALL连接这两个查询;如果你想要将一组结果附加到另一组结果的末尾,则可以这样做。
请忽略我的第一个答案,因为那样做不能得到你想要的结果。抱歉。
如果你希望输出有重复的列,在这种情况下,SIoC1PIoC1本质上是相同的,但名称不同,具体取决于行来自“学校”还是“家长”,那么你的结果集将出现NULLS,例如(由于你没有提供示例数据,因此使用随机数据)。
| A.Id | SIoC1 | SIoCScore1 | PIoC1 | PIoCScore1 |
   1      A          10       NULL      NULL       -- Row type 'School'
   2     NULL       NULL       B        20         -- Row type 'Parent'   
etc. etc.

如果数据存储在同一张表中,并且使用相同的字段名称,请使用其他字段来区分行,例如Type,并在结果中显示它。


我已经更新了我的问题,并提供了一些领域背景 - 谢谢 - laura

2

一个查询可能就足够了:

SELECT 
  A.Id, A.Type, C1.Topic AS IoC1, C1.Level AS IoCScore1
FROM Assessment A
  LEFT JOIN Concern C1 ON A.Id = Assessment_Id and C1.TopicNumber = 1
WHERE A.Type IN ('School', 'Parent')

谢谢回复,不幸的是这没有保留学校和家长列。 - laura

2
我认为这个查询必须返回与“Further Update”部分中的查询结果相同。
P.Type = ...条件从WHERE移动到ON部分,因此您可以在不使用连接子选择的情况下获得所需的效果。
SELECT
  P.StudentId,
  CS.Topic AS TIoC1,
  CS.Level AS TIoCScore1,
  CP.Topic AS PIoC1,
  CP.Level AS PIoCScore1 
FROM
  Assessment P
    LEFT JOIN Concern CS ON P.Id = CS.Assessment_Id
      and CS.TopicNumber = 1 and P.Type = 'School'
    LEFT JOIN Concern CP ON P.Id = CP.Assessment_Id
      and CP.TopicNumber = 1 and P.Type = 'Parent'

编辑:看起来分组应该有帮助。 (我保留我的最初查询,以便更容易地查看更新后的要求所需的更改。)

SELECT
  P.StudentId,
  MAX(CS.Topic) AS TIoC1,
  MAX(CS.Level) AS TIoCScore1,
  MAX(CP.Topic) AS PIoC1,
  MAX(CP.Level) AS PIoCScore1 
FROM
  Assessment P
    LEFT JOIN Concern CS ON P.Id = CS.Assessment_Id
      and CS.TopicNumber = 1 and P.Type = 'School'
    LEFT JOIN Concern CP ON P.Id = CP.Assessment_Id
      and CP.TopicNumber = 1 and P.Type = 'Parent'
GROUP BY P.StudentId

谢谢您的回复,但这并不完全是我想要的,因为它会为每个评估创建两行。 - laura

1

您可以在一个查询中选择所有内容,并使用CASE语句仅填充适用的值。

SELECT
  A.Id, 
  CASE A.Type
    WHEN 'School' 
      THEN C1.Topic
    ELSE NULL
  END
  AS SIoC1, 
  CASE A.Type
    WHEN 'School' 
      THEN C1.Level
    ELSE NULL
  END
  AS SIoCScore1,
  CASE A.Type
    WHEN 'Parent' 
      THEN C1.Topic
    ELSE NULL
  END
  AS PIoC1, 
  CASE A.Type
    WHEN 'Parent' 
      THEN C1.Level
    ELSE NULL
  END AS PIoCScore1  
FROM Assessment A
  LEFT JOIN Concern C1 ON A.Id = Assessment_Id and C1.TopicNumber = 1
WHERE A.Type IN ('School', 'Parent')

编辑:最好存储Type列,这样您就可以区分所需的两种数据类型,然后您就不必像上面的示例中那样重复列。如果您正在创建一个表,则为了符合某种规范化形式,您不希望有重复的列,但是如果您在视图中使用此选择语句,则可以接受这样做。


0

结果列的名称必须相同(使用别名)且数据类型相同:

SELECT 
  A.Id, C1.Topic AS Topic, C1.Level AS Level
FROM Assessment A
  LEFT JOIN Concern C1 ON A.Id = Assessment_Id and C1.TopicNumber = 1
WHERE A.Type = 'School'

UNION

SELECT 
  A.Id, C1.Topic AS Topic, C1.Level AS Level
FROM Assessment A
  LEFT JOIN Concern C1 ON A.Id = Assessment_Id and C1.TopicNumber = 1
WHERE A.Type = 'Parent'

起初我给出了相同的答案,但后来意识到 OP 想要的最终结果集与这两个查询的列不同。 - Tony

0

尝试这个解决方案

    SELECT * INTO #School FROM
     (
      SELECT 
        A.StudentId, C1.Topic AS SIoC1, C1.Level AS SIoCScore1
      FROM Assessment A
      LEFT JOIN Concern C1 ON A.Id = Assessment_Id and C1.TopicNumber = 1
      WHERE A.Type = 'School'
       )school

    SELECT * INTO #Parent FROM
    (
     SELECT 
       A.StudentId, C1.Topic AS PIoC1, C1.Level AS PIoCScore1
      FROM Assessment A
      LEFT JOIN Concern C1 ON A.Id = Assessment_Id and C1.TopicNumber = 1
     WHERE A.Type = 'Parent'
    )parent

   SELECT 
   SL.StudentId
  ,SL.SIoC1
  ,SL.SIoCScore1
  ,PT.PIoC1
  ,PT.PIoCScore1 
 From #School SL
 LEFT JOIN #Parent PT ON PT.StudentId = SL.StudentId

0
SELECT
  A.Id, 
  CASE A.Type
    WHEN 'School' 
      THEN C1.Topic
    ELSE NULL
  END
  AS SIoC1, 
  CASE A.Type
    WHEN 'School' 
      THEN C1.Level
    ELSE NULL
  END
  AS SIoCScore1,
  CASE A.Type
    WHEN 'Parent' 
      THEN C1.Topic
    ELSE NULL
  END
  AS PIoC1, 
  CASE A.Type
    WHEN 'Parent' 
      THEN C1.Level
    ELSE NULL
  END AS PIoCScore1  
FROM Assessment A
  LEFT JOIN Concern C1 ON A.Id = Assessment_Id and C1.TopicNumber = 1
WHERE A.Type IN ('School', 'Parent')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接