如何编写此查询而不是GROUP BY中的所有列

时间:2017-05-07 09:31:41

标签: sql sql-server

以下查询

SELECT child.* 
FROM [nested-set] AS parent
JOIN (
  SELECT [lft] AS parentLft, [rgt] AS parentRgt 
  FROM [nested-set] WHERE [id] = 3
) AS parent2 ON 1=1
JOIN [nested-set] AS child ON child.[lft] BETWEEN parent.[lft] AND parent.[rgt] 
WHERE parent.[lft] >= parentLft AND parent.[rgt] < parentRgt AND parent.[id] > 1 
GROUP BY child.[id] 
HAVING COUNT(child.[id]) = 1 
ORDER BY child.[lft] ASC

在嵌套集模型中获取节点的子节点,在MySQL和SQLite上运行完全正常(当然使用不同的列引用)但是为了使它在MS SQL Server上工作,我必须添加所有列GROUP BY子句。由于此查询应该在不同的表上运行,这些表只有id,lft和rgt列共同必须指定所有列,每次都是过度杀伤。有解决方案吗?

1 个答案:

答案 0 :(得分:1)

您可以使用返回所需Id的子查询,然后将主表链接到该子查询。

这样您就不需要在外部查询中指定列。

SELECT t.* 
FROM(
    SELECT child.id
    FROM [nested-set] headparent
    JOIN [nested-set] parent ON (parent.lft >= headparent.lft AND parent.rgt < headparent.rgt)
    JOIN [nested-set] child ON (child.lft BETWEEN parent.lft AND parent.rgt)
    WHERE headparent.id = 3 
      AND parent.id > 1
    GROUP BY child.id
    HAVING count(*) = 1
) q
JOIN [nested-set] t ON t.id = q.id
ORDER BY t.lft ASC;

由于这几乎是“旧标准SQL”(f.e。不使用窗口函数),因此它也适用于MySql或SQLite。

发布脚本:

我想知道是否可以使用EXISTS。
从下面的实验来看,确实如此。如果您不使用GROUP BY 但是i.m.h.o.,第一种方法是更直接的方法来实现它。

declare @NestedSet table (id int, lft int, rgt int, colA int);

insert into @NestedSet (id,lft,rgt,colA) values
(1,3,5,100),
(2,4,5,200),
(3,3,6,300),
(4,3,5,400),
(5,4,6,500);

select *
from @NestedSet t
where exists (
    select 1
    from @NestedSet headparent
    join @NestedSet parent on (parent.lft >= headparent.lft and parent.rgt < headparent.rgt and parent.id > 1)
    where headparent.id = 3
    and t.lft between parent.lft and parent.rgt
    having count(*) = 1
);