【问题标题】:Select distinct on foreign key, inner join another table在外键上选择不同的,内连接另一个表
【发布时间】:2019-11-18 22:57:23
【问题描述】:

基本上我想做的是,选择用户最后的 3 个操作。但是 RelationId 上没有重复项,并且还有 innerjoin 权限,只是为了确保用户仍然有权执行相同的操作。

我唯一想要的权限是 RelationId。

没有重复我的意思是如果有两行具有相同 RelationId 的 Action 应该选择靠近顶部的那一行(按 TimeStamp 排序)。

到目前为止我想出了什么:

SELECT DISTINCT a.*, p.RelationId
FROM [Action] [a]
INNER JOIN [Permission] p 
  ON ([p].[RelationId] = [a].[RelationId] 
  AND [p].[RelationType] = [a].[RelationType] 
  AND [p].[UserId] = [a].[UserId] 
  AND [p].[Deleted] = 0)
WHERE [a].[ActionType] = 'Clicked' 
AND [a].[RelationType] = 'Direct' 
AND [a].[UserId] = 5 
AND [a].[Deleted] = 0
ORDER BY [a].[TimeStamp] DESC
OFFSET 0 ROWS
FETCH NEXT 3 ROWS ONLY

分页只需要使用OFFSET X ROWS和FETCH NEXT 3 ROWS

由于某种原因,这不起作用,因为我在 RelationId 上得到了重复项。 没有错误。

示例数据:

action (
    id            INTEGER       PRIMARY KEY,
    ActionType    VARCHAR(50)   not null,
    RelationId    INTEGER       ForeignKey,
    Deleted       Bit           not null,
    TimeStamp     DATE          not null,
    UserId        INTEGER       ForeignKey
);

期望的结果:一个用户执行的最后 3 次操作,该用户具有不同的 RelationId 权限。

【问题讨论】:

  • 样本数据作为文本表和期望的结果会有所帮助。还应添加适当的数据库标签。
  • 文本表是什么意思?
  • 样本数据最好使用DDL + DML。请edit您的问题包括它,您当前的尝试和您想要的结果。更多详情,read this.
  • 定义一个副本。你有 DISTINCT 并且应该没有重复,只要重复意味着所有列值都相同。
  • 第一句中定义,在RelationId上定义,在RelationID上没有重复

标签: sql sql-server inner-join distinct


【解决方案1】:

根据您对每个用户最后 3 个的定义(如果最后 3 个,则每个关系 ID 不能是单行):

with data as (
  SELECT *, 
  row_number() over (partition by relationId order by [timeStamp] desc) as rNo
  from action 
  where [ActionType] = 'Clicked' AND 
        [RelationType] = 'Direct' AND 
        [UserId] = 5 AND 
        [Deleted] = 0
)
select a.id,a.ActionType,a.RelationId,a.Deleted,a.TimeStamp,a.UserId,
       p.RelationId as pRelId
FROM [data] [a]
INNER JOIN [Permission] p ON ([p].[RelationId] = [a].[RelationId] AND [p].[RelationType] = [a].[RelationType] AND [p].[UserId] = [a].[UserId]) 
WHERE p.[Deleted] = 0 and a.rNo <= 3
ORDER BY [a].[TimeStamp] DESC;

【讨论】:

  • “如果最后 3 个,那么它不能是每个关系 ID 的单行)是什么意思?
  • @Charlie,这不是很明显吗?如果同一个relationId 有3 个最后的条目,那么它将计为3 行,而不是1。
  • 是的,我明白了。我的问题是是否有办法解决它。就像 distinct 的工作原理一样。
【解决方案2】:

如果我明白了,您只需要为每个 Permission 提供最新的操作,并从所有这些中保留最近的三行。这里:

select top 3 p.RelationId,top_action.*
from 
    [Permission] p
    cross apply
    (
        select top 1 *
        from [Action] [a]
        where 
            [p].[RelationId] = [a].[RelationId] AND [p].[RelationType] = [a].[RelationType] AND [p].[UserId] = [a].[UserId] 
            and [a].[ActionType] = 'Clicked' AND [a].[RelationType] = 'Direct' AND [a].[UserId] = 5 AND [a].[Deleted] = 0
        order by [a].[TimeStamp] DESC
    )top_action
where [p].[Deleted] = 0
order by top_action.[TimeStamp] DESC

【讨论】:

  • 嗨,谢谢。但我想要完成的是选择用户最后的 3 个操作,并检查他是否有权限。 (我是通过内部加入做到的)。效果很好。但是在我的代码中不起作用的是通过 RelationId 选择不同的。这将表示每个 RelationId 一行。它还需要适合分页,所以必须(我认为)OFFSET 和 FETCH NEXT 不知道该怎么做
【解决方案3】:

Distinct 将始终区分所有参数。选择 * 总是不同的。 您只需选择一个参数即可确定。

您可以使用 group by,也可以使用相同的选择分两步进行分组。像这样:

select * from Action where id in (
SELECT DISTINCT a.id
FROM [Action] [a]
INNER JOIN [Permission] p 
  ON ([p].[RelationId] = [a].[RelationId] 
  AND [p].[RelationType] = [a].[RelationType] 
  AND [p].[UserId] = [a].[UserId] 
  AND [p].[Deleted] = 0)
WHERE [a].[ActionType] = 'Clicked' 
AND [a].[RelationType] = 'Direct' 
AND [a].[UserId] = 5 
AND [a].[Deleted] = 0
ORDER BY [a].[TimeStamp] DESC
OFFSET 0 ROWS
FETCH NEXT 3 ROWS ONLY
)

【讨论】:

    【解决方案4】:

    通过这样做解决了它。不知道这是否是最好的解决方案。

    SELECT [a].*, [p].[Id]
    FROM (SELECT *, ROW_NUMBER() OVER(PARTITION BY [RelationId] ORDER BY [TimeStamp] DESC) AS row from [Action]) a
    INNER JOIN [Permission] p ON ([ep].[RelationId] = [a].[RelationId] AND [p].[RelationType] = [a].[RelationType] AND [p].[UserId] = [a].[UserId] AND [p].[Deleted] = 0)
    WHERE row = 1 AND [a].[ActionType] = 'Clicked' AND [a].[RelationType] = 'Direct' AND [a].[UserId] = 5 AND [a].[Deleted] = 0
    ORDER BY [a].[TimeStamp] DESC
    OFFSET 0 ROWS
    FETCH NEXT 3 ROWS ONLY
    

    【讨论】:

      猜你喜欢
      • 2012-12-18
      • 1970-01-01
      • 2020-03-21
      • 2022-01-19
      • 2018-02-12
      • 2018-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多