【问题标题】:Set column value if certain record exists in same table如果同一表中存在某些记录,则设置列值
【发布时间】:2013-11-10 17:50:39
【问题描述】:

如果表包含某种类型的记录,我如何为表创建一个视图,其中包含表记录的子集、表的所有列以及附加的“标志”列,其值设置为“X”?例如,考虑以下关系表Relations,其中类型的值代表H'-human, 'D'-dog

 id | type | relation | related
--------------------------------
 H1 |  H   | knows    | D2 
 H1 |  H   | owns     | D2 
 H2 |  H   | knows    | D1 
 H2 |  H   | owns     | D1
 H3 |  H   | knows    | D1
 H3 |  H   | knows    | D2
 H3 |  H   | treats   | D1
 H3 |  H   | treats   | D2
 D1 |  D   | bites    | H3
 D2 |  D   | bites    | H3

此表中可能没有任何特定的记录顺序。

我试图创建一个视图Humans,它将包含来自Relations 的所有人对狗knows 关系以及所有Relations 的列和附加列isOwner,如果存储'X'特定关系中的人拥有某人:

 id | type | relation | related | isOwner
------------------------------------------
 H1 |  H   | knows    |    D2   |    X
 H2 |  H   | knows    |    D1   |    X
 H3 |  H   | knows    |    D1   |    

但为此苦苦挣扎。你知道一种方法吗,最好是在一个CREATE VIEW 电话中,或者真的有什么方法吗?

【问题讨论】:

  • @plalx,一点也不。谢谢你们@plalx 和@1_CR 的精彩回答!我希望我能接受两者,因为最终版本是他们的组合。关于owns VS related only,我想要的是related = r.related,但不得不承认我没有在问题中正确说明这一点。再次感谢你们——你们帮了我很多!

标签: sql sql-server


【解决方案1】:
CREATE VIEW vHumanDogRelations
AS
SELECT
    id,
    type,
    relation,
    related,
    -- Consider using a bit 0/1 instead
    CASE 
        WHEN EXISTS (
            SELECT 1
            FROM Relations
            WHERE 
                id = r.id
                AND related = r.related -- Owns someone or this related only?
                AND relation = 'owns'    
        ) THEN 'X'
        ELSE ''
    END AS isOwner
FROM Relations r
WHERE 
    relation = 'knows'
    AND type = 'H'
    AND related = 'D';

【讨论】:

  • 请注意,即使 H3 不处于“拥有”关系中,这也会将 H3 标记为所有者
  • @1_CR 我现在修好了。我最初的理解没有任何意义,但我仍然认为这就是 OP 想要的;)
  • 请注意,从 OP 的角度来看,AND related = r.related 可能过于局限。引用 OP,“如果给定关系中的人拥有某人,则存储'X'”
  • @1_CR 也许,但是我实现它的方式似乎更有意义,但你是对的,所以我添加了评论。
【解决方案2】:

您应该可以将以下select 放入视图定义中

select *, case when exists 
(select * from Relations where id = r.id and relation= 'owns') then 'X'
else '' end as isOwner 
from Relations r

【讨论】:

    【解决方案3】:

    您也可以使用 PIVOT 来实现所需的结果。我将详细解释该方法,因为最终的查询可能看起来令人困惑。

    首先,从Relation 派生一个子集,其中typeHrelation 或者knowsowns,将owns 值替换为X

    SELECT
      id,
      type,
      relation = CASE relation WHEN 'owns' THEN 'X' ELSE relation END,
      related
    FROM Relations
    WHERE type = 'H'
      AND relation IN ('knows', 'owns')
    

    根据你的例子,你会得到这个:

    id  type  relation  related
    --  ----  --------  -------
    H1   H    knows     D2
    H1   H    owns      D2
    H2   H    knows     D1
    H2   H    owns      D1
    H3   H    knows     D1
    H3   H    knows     D2
    

    接下来,将此 PIVOT 子句应用于第一个查询的结果:

    PIVOT (
      MAX(relation) FOR relation IN (knows, X)
    ) AS p
    

    它将具有相同id, type, related 值的行分组为一行并将relation 拆分为两列,knowsX

    id  type  related  knows  X
    --  ----  -------  -----  ----
    H1   H    D2       knows  X
    H2   H    D1       knows  X
    H3   H    D1       knows  NULL
    H3   H    D2       knows  NULL
    

    此时您只需要重新排列主SELECT子句中为输出设置的列,将knows重命名为relationX重命名为isOwner

    SELECT
      id,
      type,
      relation = knows,
      related,
      isOwner = X
    ...
    

    输出:

    id  type  relation  related  isOwner
    --  ----  --------  -------  -------
    H1   H    knows     D2       X
    H2   H    knows     D1       X
    H3   H    knows     D1       NULL
    H3   H    knows     D2       NULL
    

    当然,如果有必要,NULL 可以很容易地用空字符串替换。

    最后一点可能是将这个额外的过滤器添加到主查询中:

    WHERE knows IS NOT NULL
    

    以防万一有人在不认识狗的情况下拥有狗(并且您不希望在输出中包含这些狗)。

    所以,完整的查询应该是这样的:

    SELECT
      id,
      type,
      relation = knows,
      related,
      isOwner = X
    FROM (
      SELECT
        id,
        type,
        relation = CASE relation WHEN 'owns' THEN 'X' ELSE relation END,
        related
      FROM Relations
      WHERE type = 'H'
        AND relation IN ('knows', 'owns')
    ) AS s
    PIVOT (
      MAX(relation) FOR relation IN (knows, X)
    ) AS p
    WHERE knows IS NOT NULL
    ;
    

    此解决方案的 SQL Fiddle 演示可用 here

    【讨论】:

    • +1 这很酷;不知道这样的事情。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2016-11-27
    • 2019-04-15
    • 2019-12-03
    • 1970-01-01
    • 1970-01-01
    • 2022-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多