根据子ID SQL获取父项

时间:2015-05-07 22:04:52

标签: sql sql-server

我在Microsoft SQL环境中有以下场景:

  #include<stdio.h>

int BinarySearch(int l, int h, int *a, int x );
  int main()

{

  int a[10], n, i, x, r=1, q=0;

  int *p= &a[0];

  printf("Enter the number of elements :\n");

  scanf("%d", &n);

  printf("Enter the elements :\n");

  for(i=0; i<n; i++)

    scanf("%d", &a[i]);

  printf("Enter the element to be searched :\n");

  scanf("%d", &x);

 r=BinarySearch(q, n-1, p, x);



  if(r==-1)

    printf("The element %d is not present in the array\n", x);

  else

  printf("The element %d is in position %d", x, r);

 return 0;

}



int BinarySearch(int l, int h, int *a, int x)

{

  while(l<=h)

  {

    int m;

    m=(l+(h-1))/2;

    if (a[m]==x)

    return m;

    if(a[m]<x)

      l=m+1;

    else

      h=m-1;

  }
  return -1;
}

我试图根据孩子的身份得到父母。如果查询的id是最后一个父项,那么它应该只返回最后一项。

示例:

  • 如果我查询:CREATE TABLE grps ( [id] varchar(50), [parentid] varchar(50), [value] varchar(50) ); INSERT INTO grps ([id], [parentid], [value]) VALUES ('-5001', '0', null), ('-5002', '-5001', null), ('-5003', '-5002', '50'), ('-5004', '-5003', null), ('-5005', '0', null), ('-5006', '0', null), ('-5007', '0', null), ('-5008', '-5006', null); ,则应返回id = '-5004'
  • 如果我查询('-5004', '-5003', null), ('-5003', '-5002', '50'), ('-5002', '-5001', null), ('-5001', '0', null),则应返回id = '-5007'

如果它可以列出首先查询的id并且其余部分以有序的方式列出&#34;树&#34;那将是非常棒的。

我已经尝试了几种不同的CTE方法,但遗憾的是没有运气。所以我在这里寻找一些帮助或想法。

提前致谢。

2 个答案:

答案 0 :(得分:3)

你和CTE一起走在了正确的轨道上。它可以通过使用递归CTE来完成!以下是递归CTE的样子:

DECLARE @ID varchar(50) = '5004';

WITH CTE AS
(
    --This is called once to get the minimum and maximum values
    SELECT id, parentid, value
    FROM grps
    WHERE id= @ID
    UNION ALL
    --This is called multiple times until the condition is met
    SELECT g.id, g.parentid, g.value
    FROM CTE c, grps g
    WHERE g.id= c.parentid
    --If you don't like commas between tables then you can replace the 2nd select 
    --statement with this:
    --SELECT g.id, g.parentid, g.value
    --FROM CTE c
    --INNER JOIN grps g ON g.id= c.parentid
    --This can also be written with CROSS JOINS! 
    --Even though it looks more like another way of writing INNER JOINs.
    --SELECT g.id, g.parentid, g.value
    --FROM CTE c
    --CROSS JOIN grps g
    --WHERE g.id = c.parentid
)

SELECT * FROM CTE

请注意,除非您将option (maxrecursion 0)添加到最后一个select语句的末尾,否则最大递归为100。 0表示无限,但您也可以将其设置为您想要的任何值。

享受!

答案 1 :(得分:2)

我正在尽力为这个世界的某种爱人提供一些爱。首先,设置:

CREATE TABLE grps
(
  [id] varchar(50),
  [parentid] varchar(50),
  [value] varchar(50),
  h HIERARCHYID NULL
);

SELECT * FROM grps
INSERT INTO grps
    ([id], [parentid], [value])
VALUES
    ('-5001', '0', null),
    ('-5002', '-5001', null),
    ('-5003', '-5002', '50'),
    ('-5004', '-5003', null),
    ('-5005', '0', null),
    ('-5006', '0', null),
    ('-5007', '0', null),
    ('-5008', '-5006', null);

WITH cte AS (
    SELECT id ,
           parentid ,
           value ,
           CAST('/' + id + '/' AS nvarchar(max)) AS h
    FROM grps
    WHERE parentid = 0

    UNION ALL

    SELECT child.id ,
           child.parentid ,
           child.value ,
           CAST(parent.h + child.id + '/' AS NVARCHAR(MAX)) AS h
    FROM cte AS [parent]
    JOIN grps AS [child]
        ON child.parentid = parent.id
)
UPDATE g
SET h = c.h
FROM grps AS g
JOIN cte AS c
    ON c.id = g.id

我在这里所做的就是在表定义中添加一个hierarchyid列并计算它的值。要确定回答原始问题,现在它看起来像这样:

SELECT g.id ,
       g.parentid ,
       g.value ,
       g.h.ToString() 
FROM dbo.grps AS g
JOIN grps AS c
    ON c.h.IsDescendantOf(g.h) = 1
WHERE c.id = '-5004'

为了提高性能,您应该独立地索引id和h列(即,在单独的索引中)。

另外,还有几个笔记

  • 当数据看起来是数字时,将id列设为varchar充其量是多余的,但更重要的是它效率低下。如果是我,我会使用int。但也许你的实际数据比较混乱(即你有像'A1234'这样的ids)。

  • 我还会使用NULL而不是0来表示parentid代表顶级(即那些没有父级的成员)。但这更多是个人选择,而不是具有任何实际性能影响的选择。