2015-11-12 59 views
0

我對SQL和所有自學的新手都很在意,所以在技術太過時請記住這一點!基於Common Column SQL Server的行合併

我有一個教堂數據庫工作。我們有一張桌子,可以將家庭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。例如,我可能想要顯示來自不同表格的某個班級中的所有家庭。

我需要一個解決方案,具有足夠的靈活性讓我身邊將其更改爲不同的列添加到根據需要的結果。

非常感謝您的幫助!

UPDATE 下面是我從貝爾巴托夫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語法。如何提出額外的列任何幫助將是真棒!

解決方案! 我得到它的工作就像我需要!以下是更多專欄和信息的工作查詢!

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 

謝謝大家的幫助!

+0

這裏有一個例子,根據家族ID將多行記錄到一行中。如果你爲父母和子女列做到這一點,你應該有你以後http://stackoverflow.com/questions/15477743/listagg-in-sqlserver – xQbert

+0

xQbert,這工作得很好,但如果我需要引入另一個表,則不會。這使我可以查看與家庭ID相關的所有人員ID,但是我需要再拉一張表格,告訴我具有該人員ID的人員的姓名。 –

回答

0

你可以嘗試stuff()功能來連接由family_id分組結果 - 這裏是一個樣品,我覺得它返回你需要什麼。

恐怕我不能讓它變得更簡單 - 不幸的是SQL服務器沒有group_concat函數,並且stuff()爲了連接目的而讀取或寫入真的很難看。您可以向兒童和家長CTE-s添加更多列,但是如果需要連接,則需要爲每個新的連接列添加單獨的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 
+0

這看起來像一個很好的解決方案。另外,感謝每個部分的詳細解釋!但我有一個問題。在INSERT INTO中,我將如何獲得所有表格的信息,而無需輸入列中的所有信息?而且我可能需要立即看到近40列。 –

+0

我能夠獲得正確的列,但以非常笨拙的方式做到了。我做了一個腳本表,並插入到。如果你知道更好的方法,我很樂意聽到它! 在我的第一篇文章中查看我的更新。 –

+0

@NickTaylor對不起,我不需要使用表變量(這只是一個工作示例) - 從CTE-s開始(即「; WITH ...」),並替換包含表名的表變量(即core_v_person_basic和core_family_member)。 –