【问题标题】:SQL select in list A but create row even when not in list ASQL在列表A中选择,但即使不在列表A中也创建行
【发布时间】:2018-12-10 12:09:18
【问题描述】:

我已尝试搜索解决方案,但找不到任何解决方案。如有重复请指正方向。

[问题]
我想查询用户 ID 列表 (('hunter1', 'hunter2', 'hunter3')) 并检查他们是否同意我们的隐私政策。
但是,这里有一个问题 - 即使用户 ID 不在我们的数据库中,我也需要该用户 ID 为“N”的行来表示政策协议状态。

[原样:当前查询]

查询解释:单个用户 ID 可以有多个条目,因为该用户可能已经加入并离开并再次加入。 简单地说,如果可以多次找到该用户 ID,则此查询返回用户 ID 及其状态,其中该用户 ID 具有最高的序列号。

SELECT
    userID,
    policyAgreementStatus
FROM
    MEMBERTABLE m
WHERE
    userNoSeq IN (
        SELECT
            MAX(userNoSeq)
        FROM
            MEMBERTABLE
        WHERE
            m.userID = MEMBERTABLE.userID AND MEMBERTABLE.userID IN 
                 ('hunter1', 'hunter2', ...)
    )
ORDER BY userNoSeq;

如果表中不存在“hunter1”,上述查询将返回如下内容。

userID      policyAgreementStatus
-----------------------------------
hunter2             Y
hunter3             N
...

[未来]

我想要一个返回的结果:

userID      policyAgreementStatus
-----------------------------------
hunter1             N
hunter2             Y
hunter3             N

即使 Hunter1 一开始不在桌子上。

我能想到的最简单的方法是创建一个临时表或使用 PL/SQL 集合并将其与原始表连接。
但是,我正在处理只读数据库,所以这是不可能。
任何想法都会有所帮助。谢谢。

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    你不需要创建对象来使用集合,有一些内置的。例如,您可以将您的 ID 列表提供为 ODCIVarchar2LIst,将其扩展为单个元素,然后左连接到您的真实表:

    WITH userIDs (userID) AS (
        SELECT
            column_value
        FROM
            TABLE(SYS.ODCIVARCHAR2LIST('hunter1', 'hunter2', 'hunter3'))
    )
    SELECT
        u.userID,
        COALESCE (
            MAX(m.policyAgreementStatus) KEEP (DENSE_RANK LAST ORDER BY m.userNoSeq),
            'N'
        ) AS policyAgreementStatus
    FROM
        userIDs u
    LEFT JOIN
        MEMBERTABLE m
    ON
        m.userID = u.userID
    GROUP BY
        u.userID
    ORDER BY userID;
    

    coalesce() 在不匹配时提供默认的 N 值,因为左连接将保留该空值。我已从您的子选择 to use max ... keep dense_rank last 切换,因为它有点短,但您的原始查询仍然可以工作。

    您可能已经有自己的集合类型可用,具体如何实现取决于值列表的来源以及它是如何(或可以)提供给查询的。

    【讨论】:

      【解决方案2】:

      您可以使用LEFT 外连接和MAX 解析函数。一个 CTE 保存所有的用户 ID。

      with h(userID) as
      (
        select 'hunter1' from dual union all 
        select 'hunter2' from dual union all 
        select 'hunter3' from dual 
      )
      SELECT userID,
          COALESCE(policyAgreementStatus,'N') AS policyAgreementStatus
      FROM
      ( SELECT
          h.userID,
          m.userNoSeq,
          m.policyAgreementStatus,
          COALESCE (
              MAX(m.userNoSeq) OVER (partition by h.userID ),
              0
          ) AS max_userNoSeq
      FROM
          h 
      LEFT OUTER JOIN
          MEMBERTABLE m
      ON m.userID = h.userID
          ) WHERE max_userNoSeq IN ( userNoSeq,0) ;
      

      【讨论】:

        【解决方案3】:

        我会这样做:

        select m.userid,
               coalesce(max(mt.policyAgreementStatus) keep (dense_rank first order by userNoSeq desc),
                        'N'
                       ) as policyAgreementStatus
        from (select 'hunter1' as userid from dual union all 
              select 'hunter2' from dual union all 
              select 'hunter3' from dual 
             ) m left join
             membertable mt
             on mt.userid = m.userid
        group by m.userid;
        

        您可以使用keep 语法获取最新的policyAgreementStatus。我发现这在 Oracle 中非常有效。

        【讨论】:

          猜你喜欢
          • 2022-01-09
          • 1970-01-01
          • 2021-06-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-25
          相关资源
          最近更新 更多