基于公共列SQL Server

时间:2015-11-12 17:17:44

标签: sql sql-server

我对SQL非常陌生并且都是自学成才所以请在技术过时时牢记这一点!

我正在使用教会数据库。我们有一张桌子,可以为家庭成员分配家庭ID。我有一个包含所有系列ID的表,并且有一个列,其中包含与该系列ID关联的唯一人员ID。当我针对查找特定系列ID的表运行查询时,我会为与该系列ID关联的每个唯一身份ID获取一行。

我需要做的是将这些家庭组合成一行,在一列中显示成人的名字,在另一列中显示孩子的名字。然后是列中的姓氏和列中的地址。

当我使用它时,我可以成功地做到这一点:

DECLARE @FirstNames VARCHAR (MAX)
DECLARE @Children VARCHAR (MAX)
DECLARE @Address VARCHAR (MAX)
DECLARE @LastName VARCHAR (MAX)

SELECT @FirstNames = COALESCE(@FirstNames+', ','') + pb.first_name,
@Address = pb.Address,
@LastName = pb.last_name
FROM core_v_person_basic pb
JOIN core_family_member fm ON fm.person_id = pb.person_id
WHERE fm.role_luid = 29
AND fm.family_id = 13783

SELECT @Children = COALESCE(@Children+', ','') + pb.first_name
FROM core_v_person_basic pb
JOIN core_family_member fm ON fm.person_id = pb.person_id
WHERE fm.role_luid = 31
AND fm.family_id = 13783

SELECT
@FirstNames AS 'First Names',
@LastName AS 'Last Name',
@Children AS 'Children',
@Address AS 'Address'

但问题是这只适用于一个家庭ID。我希望能够以这种方式显示所有族ID,或者显示一组特定的家庭ID。例如,我可能想要显示某个类中将来自不同表的所有族。

我需要一个足够灵活的解决方案,让我可以根据需要更改它以在结果中添加不同的列。

非常感谢您的帮助!

更新 这是我从Dimitar Kyuchukov的答案修改的查询: - 为了样本的目的模拟表格(你可以用代码中的表名替换这些变量,直到样本结束):

DECLARE @core_family_member AS TABLE 
           (family_id int,
           person_id int,
           date_created datetime,
           date_modified datetime,
           created_by varchar(50),
           modified_by varchar(50),
           role_luid int,
           organization_id int)

DECLARE @core_v_person_basic AS TABLE (
           person_id int,
           guid uniqueidentifier,
           suffix varchar(50),
           nick_name nvarchar(50),
           first_name nvarchar(50),
           last_name nvarchar(50),
           birth_date datetime,
           address_id int,
           Address varchar(201),
           street_address_1 varchar(100),
           street_address_2 varchar(100),
           city varchar(64),
           state varchar(12),
           postal_code varchar(24),
           member_status_luid int,
           member_status varchar(50),
           record_status varchar(8),
           gender varchar(1),
           marital_status_luid int,
           marital_status varchar(50),
           home_phone varchar(50),
           list_home_phone varchar(50),
           business_phone varchar(50),
           list_business_phone varchar(50),
           cell_phone varchar(50),
           list_cell_phone varchar(50),
           email varchar(80),
           area_id int,
           area_name varchar(100),
           organization_id int,
           photo_guid varchar(80),
           envelope_number int,
           restricted bit)
INSERT INTO 
    @core_v_person_basic

SELECT * FROM core_v_person_basic

INSERT INTO 
    @core_family_member

SELECT * FROM core_family_member

-- Here children and parents are selected separately with a family ID to join by (these are called CTE-s for Common Table Expression - they will make the final statement more clear):
;WITH 
Children AS (
    SELECT 
        fm.family_id,
        pb.first_name AS child_first_name
    FROM 
        @core_v_person_basic pb
        INNER JOIN @core_family_member fm 
            ON fm.person_id = pb.person_id
    WHERE
        fm.role_luid = 31
),
Parents AS (
    SELECT 
        fm.family_id,
        pb.first_name AS parent_first_name
    FROM 
        @core_v_person_basic pb
        INNER JOIN @core_family_member fm 
            ON fm.person_id = pb.person_id
    WHERE
        fm.role_luid = 29
),
Address AS (
    SELECT
        pb.address AS 'Address'
    FROM
        @core_v_person_basic pb)

-- Here stuff() function is used to concatenate the members grouped by family ID - basically an XML is "stuffed" similar to your variables and then the ready value is taken using the value() function:
SELECT
    stuff((
            SELECT 
                ', ' + p.parent_first_name 
            FROM
                Parents p
            WHERE 
                f.family_id = p.family_id
            FOR XML PATH(''), TYPE
        ).value('(./text())[1]', 'VARCHAR(MAX)')
        , 1, 1, '') AS parents_names,
    stuff((
            SELECT 
                ', ' + c.child_first_name 
            FROM
                Children c
            WHERE 
                f.family_id = c.family_id
            FOR XML PATH(''), TYPE
        ).value('(./text())[1]', 'VARCHAR(MAX)')
        , 1, 1, '') AS children_names

FROM
    Parents f
GROUP BY
    f.family_id

这更接近我的需要,但我仍然无法添加任何已有的列。这似乎是因为Group By语法。任何有关如何调出额外列的帮助都会很棒!

解<!/ em>的 我按照我的需要工作了!这是包含更多列和信息的工作查询!

WITH 
Children AS (
    SELECT 
        fm.family_id,
        pb.first_name AS child_first_name
    FROM 
        core_v_person_basic pb
        INNER JOIN core_family_member fm 
            ON fm.person_id = pb.person_id
    WHERE
        fm.role_luid = 31
),
Parents AS (
    SELECT 
        fm.family_id,
        pb.Address,
        pb.city,
        pb.state,
        pb.postal_code,
        pb.record_status,
        pb.last_name,
        pb.first_name AS parent_first_name
    FROM 
        core_v_person_basic pb
        INNER JOIN core_family_member fm 
            ON fm.person_id = pb.person_id
    WHERE
        fm.role_luid = 29
),
RecordStatus AS (
    SELECT
        fm.family_id,
        pb.record_status AS record_status
    FROM
        core_v_person_basic pb
        JOIN core_family_member fm On fm.person_id = pb.person_id
),
InactiveReason AS (
    SELECT
        fm.family_id,
        ir.inactive_reason_value AS inactive_reason
    FROM
        core_person cp
        JOIN core_family_member fm ON cp.person_id = fm.person_id
        JOIN core_v_inactive_reason ir ON ir.inactive_reason_id = cp.inactive_reason_luid
)

-- Here stuff() function is used to concatenate the members grouped by family ID - basically an XML is "stuffed" similar to your variables and then the ready value is taken using the value() function:
SELECT
    stuff((
            SELECT 
                ', ' + p.parent_first_name
            FROM
                Parents p
            WHERE 
                f.family_id = p.family_id
            FOR XML PATH(''), TYPE
        ).value('(./text())[1]', 'VARCHAR(MAX)')
        , 1, 1, '') AS 'First Name(s)',
f.last_name,
    stuff((
            SELECT 
                ', ' + c.child_first_name 
            FROM
                Children c
            WHERE 
                f.family_id = c.family_id
            FOR XML PATH(''), TYPE
        ).value('(./text())[1]', 'VARCHAR(MAX)')
        , 1, 1, '') AS 'Children',

f.Address,
f.city,
f.state,
f.postal_code,
 STUFF((
            SELECT
                ', ' + r.record_status
            FROM
                RecordStatus r
            WHERE
                f.family_id = r.family_id
            FOR XML PATH(''), TYPE
        ).value('(./text())[1]', 'VARCHAR(MAX)')
        , 1, 1, '') AS 'Record Status',
 STUFF((
            SELECT
                ', ' + i.inactive_reason
            FROM
                InactiveReason i
            WHERE
                f.family_id = i.family_id
            FOR XML PATH(''), TYPE
        ).value('(./text())[1]', 'VARCHAR(MAX)')
        , 1, 1, '') AS 'Record Status'
FROM
    Parents f
GROUP BY
    f.family_id,
    f.Address,
    f.city,
    f.state,
    f.postal_code,
    f.last_name

感谢大家的帮助!

1 个答案:

答案 0 :(得分:0)

您可以尝试使用stuff()函数来连接按family_id分组的结果 - 这是一个示例,我认为它会返回您需要的内容。

我担心我不能让它变得更简单 - 遗憾的是,SQL服务器没有group_concat函数,stuff()对于连接目的来说,读取或写入真的很难看。您可以向Children和Parents CTE添加更多列,但如果需要连接,则需要为每个新连接列添加单独的stuff()调用。

-- Simulate your tables for sample's sake (you would replace these variables with your table names in the code till the end of the sample), this is just demo:
DECLARE @core_v_person_basic AS TABLE (
    person_id INT,
    first_name VARCHAR(30)
)

DECLARE @core_family_member AS TABLE (
    person_id INT,
    role_luid INT,
    family_id INT
)

INSERT INTO 
    @core_v_person_basic
VALUES
    --- family 1
    (1, 'Alexander'),
    (2, 'Diana'),
    (3, 'Nick'),
    (4, 'Betty'),
    --- family 2
    (5, 'Gustav'),
    (6, 'Lory'),
    (7, 'Peter'),
    (8, 'Ally'),
    --- family 3 (no children here)
    (9, 'Chuck'),
    (10, 'Sarah')

INSERT INTO 
    @core_family_member
VALUES
    --- family 1
    (1, 29, 1),
    (2, 29, 1),
    (3, 31, 1),
    (4, 31, 1),
    --- family 2
    (5, 29, 2),
    (6, 29, 2),
    (7, 31, 2),
    (8, 31, 2),
    --- family 3
    (9, 29, 3),
    (10, 29, 3)

-- End of demo data preparation, below comes the actual sample.

-- Here children and parents are selected separately with a family ID to join by (these are called CTE-s for Common Table Expression - they will make the final statement more clear):
;WITH 
Children AS (
    SELECT 
        fm.family_id,
        pb.first_name AS child_first_name
    FROM 
        -- you should use your table names here, not the demo variables:
        @core_v_person_basic pb
        INNER JOIN @core_family_member fm 
            ON fm.person_id = pb.person_id
    WHERE
        fm.role_luid = 31
),
Parents AS (
    SELECT 
        fm.family_id,
        pb.first_name AS parent_first_name
    FROM 
        -- you should use your table names here, not the demo variables:
        @core_v_person_basic pb
        INNER JOIN @core_family_member fm 
            ON fm.person_id = pb.person_id
    WHERE
        fm.role_luid = 29
)

-- Here stuff() function is used to concatenate the members grouped by family ID - basically an XML is "stuffed" similar to your variables and then the ready value is taken using the value() function:
SELECT
    stuff((
            SELECT 
                ',' + p.parent_first_name 
            FROM
                Parents p
            WHERE 
                f.family_id = p.family_id
            FOR XML PATH(''), TYPE
        ).value('(./text())[1]', 'VARCHAR(MAX)')
        , 1, 1, '') AS parents_names,
    stuff((
            SELECT 
                ',' + c.child_first_name 
            FROM
                Children c
            WHERE 
                f.family_id = c.family_id
            FOR XML PATH(''), TYPE
        ).value('(./text())[1]', 'VARCHAR(MAX)')
        , 1, 1, '') AS children_names
FROM
    Parents f
GROUP BY
    family_id