SQL自联接状态获胜者查询

时间:2023-02-05 00:17:34

I have a customer table that has a self join (Parent - Child), I need to write a query that returns the child customer/s where the Status Allows the parent or child to place an order. The column is a bit column and is nullable.

我有一个具有自联接的客户表(父 - 子),我需要编写一个查询,返回子客户,其中状态允许父母或子女下订单。该列是一个位列,可以为空。

The results returned would be based on the following matrix:

返回的结果将基于以下矩阵:

parent_status   child_status    Child is allowed to Order
null                 null           FALSE
null                 0              FALSE
null                 1              TRUE
1                    null           TRUE
1                    1              TRUE
1                    0              FALSE
0                    null           FALSE
0                    1              FALSE
0                    0              FALSE

as requested here is schema and script for data

这里要求的是数据的模式和脚本

    CREATE TABLE [dbo].[Customer](
    [Customer_id] [int] NOT NULL,
    [ParentCustomer_id] [int] NULL,
    [Name_desc] [nvarchar](50) NULL,
    [OrderIsAllowed_status] [bit] NULL)
GO
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(1,null,'Parent 1',1)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(2,1,'Parent 1 - Child 1',null)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(3,1,'Parent 1 - Child 2',0)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(4,1,'Parent 1 - Child 3',1)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(5,null,'Parent 2',null)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(6,5,'Parent 2 - Child 1',null)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(7,5,'Parent 2 - Child 2',1)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(8,5,'Parent 2 - Child 3',0)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(9,null,'Parent 3',0)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(10,9,'Parent 3 - Child 1',null)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(11,9,'Parent 3 - Child 2',1)
insert Customer
([Customer_id],[ParentCustomer_id],[Name_desc] ,[OrderIsAllowed_status])
values(12,9,'Parent 3 - Child 3',0)

3 个解决方案

#1


1  

Based on the truth table, the CASE WHEN for it would be something like below.

基于真值表,CASE WHEN对于它将如下所示。

The example uses a table variable just for demonstration.

该示例使用表变量仅用于演示。

declare @Customer table (Customer_id int NOT NULL, ParentCustomer_id int, OrderIsAllowed_status bit);

insert @Customer ([Customer_id], [ParentCustomer_id], [OrderIsAllowed_status]) values
(1,null,1),
(2,1,null),
(3,1,0),
(4,1,1),
(5,null,null),
(6,5,null),
(7,5,1),
(8,5,0),
(9,null,0),
(10,9,null),
(11,9,1),
(12,9,0);

select 
child.Customer_id, 
child.ParentCustomer_id,
(case 
 when child.ParentCustomer_id is null then 'Parent '+ cast(child.Customer_id as varchar)
 else concat('Parent ',parent.Customer_id,' - Child ',child.Customer_id)
 end) as Name_desc,
parent.OrderIsAllowed_status as parent_status,
child.OrderIsAllowed_status as child_status,
cast(case 
     when child.OrderIsAllowed_status = 1 and parent.OrderIsAllowed_status = 1 then 1
     when child.OrderIsAllowed_status = 1 and parent.OrderIsAllowed_status is null then 1
     when child.OrderIsAllowed_status is null and parent.OrderIsAllowed_status = 1 then 1
     else 0 
     end as bit) as [Child is allowed to Order]
from @Customer child
left join @Customer parent on (child.ParentCustomer_id = parent.Customer_id);

#2


1  

You can use recursive CTE:

您可以使用递归CTE:

;WITH rec AS (
    SELECT  Customer_id,
            ParentCustomer_id,
            Name_desc,
            OrderIsAllowed_status,
            CAST(NULL AS bit) as parent_status,
            1 as [Level]
    FROM #Customer c
    WHERE ParentCustomer_id IS NULL
    UNION ALL
    SELECT  c.Customer_id,
            c.ParentCustomer_id,
            c.Name_desc,
            c.OrderIsAllowed_status,
            r.OrderIsAllowed_status,
            r.[Level]+ 1
    FROM rec r
    INNER JOIN #Customer c
        ON c.ParentCustomer_id = r.Customer_id
)

SELECT  r.Customer_id,
        r.ParentCustomer_id,
        r.Name_desc,
        r.OrderIsAllowed_status,
        rs.[Child is allowed to Order]
FROM rec r
INNER JOIN #rules rs
    ON COALESCE(r.[OrderIsAllowed_status],2) = COALESCE(rs.child_status,2)
        AND COALESCE(r.parent_status,2) = COALESCE(rs.parent_status,2)
WHERE r.ParentCustomer_id IS NOT NULL

Output:

输出:

Customer_id ParentCustomer_id   Name_desc           OrderIsAllowed_status   Child is allowed to Order
10          9                   Parent 3 - Child 1  NULL                    FALSE
11          9                   Parent 3 - Child 2  1                       FALSE
12          9                   Parent 3 - Child 3  0                       FALSE
6           5                   Parent 2 - Child 1  NULL                    FALSE
7           5                   Parent 2 - Child 2  1                       TRUE
8           5                   Parent 2 - Child 3  0                       FALSE
2           1                   Parent 1 - Child 1  NULL                    TRUE
3           1                   Parent 1 - Child 2  0                       FALSE
4           1                   Parent 1 - Child 3  1                       TRUE

I have used this tables:

我用过这个表:

CREATE TABLE #Customer (
    [Customer_id] [int] NOT NULL,
    [ParentCustomer_id] [int] NULL,
    [Name_desc] [nvarchar](50) NULL,
    [OrderIsAllowed_status] [bit] NULL
)

INSERT INTO #Customer VALUES
(1,null,'Parent 1',1),
(2,1,'Parent 1 - Child 1',null),
(3,1,'Parent 1 - Child 2',0),
(4,1,'Parent 1 - Child 3',1),
(5,null,'Parent 2',null),
(6,5,'Parent 2 - Child 1',null),
(7,5,'Parent 2 - Child 2',1),
(8,5,'Parent 2 - Child 3',0),
(9,null,'Parent 3',0),
(10,9,'Parent 3 - Child 1',null),
(11,9,'Parent 3 - Child 2',1),
(12,9,'Parent 3 - Child 3',0)

CREATE TABLE #rules (
    parent_status bit NULL,
    child_status bit NULL,
    [Child is allowed to Order] nvarchar(5) NULL
)

INSERT INTO #rules VALUES
(null, null, 'FALSE'),
(null, 0, 'FALSE'),
(null, 1, 'TRUE'),
(1, null, 'TRUE'),
(1, 1, 'TRUE'),
(1, 0, 'FALSE'),
(0, null, 'FALSE'),
(0, 1, 'FALSE'),
(0, 0, 'FALSE')

#3


0  

I have attempted to answer my own question...what would be wrong with the following ...if I was looking to return only the child customers that were allowed to place an order:

我试图回答我自己的问题......以下内容会出现什么问题...如果我想要只返回允许下订单的儿童客户:

 select p.Customer_id
    ,p.Name_desc
    ,p.OrderIsAllowed_status as Parent_IsAllowed
    ,c.Customer_id
    ,c.ParentCustomer_id
    ,c.Name_desc
    ,c.OrderIsAllowed_status    
from Customer p
inner join Customer c
    on p.customer_id = c.ParentCustomer_id
where 
    (p.OrderIsAllowed_status is null and c.OrderIsAllowed_status =1)
    or(p.OrderIsAllowed_status = 1 and c.OrderIsAllowed_status is null)
    or (p.OrderIsAllowed_status = 1 and c.OrderIsAllowed_status = 1)

#1


1  

Based on the truth table, the CASE WHEN for it would be something like below.

基于真值表,CASE WHEN对于它将如下所示。

The example uses a table variable just for demonstration.

该示例使用表变量仅用于演示。

declare @Customer table (Customer_id int NOT NULL, ParentCustomer_id int, OrderIsAllowed_status bit);

insert @Customer ([Customer_id], [ParentCustomer_id], [OrderIsAllowed_status]) values
(1,null,1),
(2,1,null),
(3,1,0),
(4,1,1),
(5,null,null),
(6,5,null),
(7,5,1),
(8,5,0),
(9,null,0),
(10,9,null),
(11,9,1),
(12,9,0);

select 
child.Customer_id, 
child.ParentCustomer_id,
(case 
 when child.ParentCustomer_id is null then 'Parent '+ cast(child.Customer_id as varchar)
 else concat('Parent ',parent.Customer_id,' - Child ',child.Customer_id)
 end) as Name_desc,
parent.OrderIsAllowed_status as parent_status,
child.OrderIsAllowed_status as child_status,
cast(case 
     when child.OrderIsAllowed_status = 1 and parent.OrderIsAllowed_status = 1 then 1
     when child.OrderIsAllowed_status = 1 and parent.OrderIsAllowed_status is null then 1
     when child.OrderIsAllowed_status is null and parent.OrderIsAllowed_status = 1 then 1
     else 0 
     end as bit) as [Child is allowed to Order]
from @Customer child
left join @Customer parent on (child.ParentCustomer_id = parent.Customer_id);

#2


1  

You can use recursive CTE:

您可以使用递归CTE:

;WITH rec AS (
    SELECT  Customer_id,
            ParentCustomer_id,
            Name_desc,
            OrderIsAllowed_status,
            CAST(NULL AS bit) as parent_status,
            1 as [Level]
    FROM #Customer c
    WHERE ParentCustomer_id IS NULL
    UNION ALL
    SELECT  c.Customer_id,
            c.ParentCustomer_id,
            c.Name_desc,
            c.OrderIsAllowed_status,
            r.OrderIsAllowed_status,
            r.[Level]+ 1
    FROM rec r
    INNER JOIN #Customer c
        ON c.ParentCustomer_id = r.Customer_id
)

SELECT  r.Customer_id,
        r.ParentCustomer_id,
        r.Name_desc,
        r.OrderIsAllowed_status,
        rs.[Child is allowed to Order]
FROM rec r
INNER JOIN #rules rs
    ON COALESCE(r.[OrderIsAllowed_status],2) = COALESCE(rs.child_status,2)
        AND COALESCE(r.parent_status,2) = COALESCE(rs.parent_status,2)
WHERE r.ParentCustomer_id IS NOT NULL

Output:

输出:

Customer_id ParentCustomer_id   Name_desc           OrderIsAllowed_status   Child is allowed to Order
10          9                   Parent 3 - Child 1  NULL                    FALSE
11          9                   Parent 3 - Child 2  1                       FALSE
12          9                   Parent 3 - Child 3  0                       FALSE
6           5                   Parent 2 - Child 1  NULL                    FALSE
7           5                   Parent 2 - Child 2  1                       TRUE
8           5                   Parent 2 - Child 3  0                       FALSE
2           1                   Parent 1 - Child 1  NULL                    TRUE
3           1                   Parent 1 - Child 2  0                       FALSE
4           1                   Parent 1 - Child 3  1                       TRUE

I have used this tables:

我用过这个表:

CREATE TABLE #Customer (
    [Customer_id] [int] NOT NULL,
    [ParentCustomer_id] [int] NULL,
    [Name_desc] [nvarchar](50) NULL,
    [OrderIsAllowed_status] [bit] NULL
)

INSERT INTO #Customer VALUES
(1,null,'Parent 1',1),
(2,1,'Parent 1 - Child 1',null),
(3,1,'Parent 1 - Child 2',0),
(4,1,'Parent 1 - Child 3',1),
(5,null,'Parent 2',null),
(6,5,'Parent 2 - Child 1',null),
(7,5,'Parent 2 - Child 2',1),
(8,5,'Parent 2 - Child 3',0),
(9,null,'Parent 3',0),
(10,9,'Parent 3 - Child 1',null),
(11,9,'Parent 3 - Child 2',1),
(12,9,'Parent 3 - Child 3',0)

CREATE TABLE #rules (
    parent_status bit NULL,
    child_status bit NULL,
    [Child is allowed to Order] nvarchar(5) NULL
)

INSERT INTO #rules VALUES
(null, null, 'FALSE'),
(null, 0, 'FALSE'),
(null, 1, 'TRUE'),
(1, null, 'TRUE'),
(1, 1, 'TRUE'),
(1, 0, 'FALSE'),
(0, null, 'FALSE'),
(0, 1, 'FALSE'),
(0, 0, 'FALSE')

#3


0  

I have attempted to answer my own question...what would be wrong with the following ...if I was looking to return only the child customers that were allowed to place an order:

我试图回答我自己的问题......以下内容会出现什么问题...如果我想要只返回允许下订单的儿童客户:

 select p.Customer_id
    ,p.Name_desc
    ,p.OrderIsAllowed_status as Parent_IsAllowed
    ,c.Customer_id
    ,c.ParentCustomer_id
    ,c.Name_desc
    ,c.OrderIsAllowed_status    
from Customer p
inner join Customer c
    on p.customer_id = c.ParentCustomer_id
where 
    (p.OrderIsAllowed_status is null and c.OrderIsAllowed_status =1)
    or(p.OrderIsAllowed_status = 1 and c.OrderIsAllowed_status is null)
    or (p.OrderIsAllowed_status = 1 and c.OrderIsAllowed_status = 1)