Inserting a concatenated value from a specific row into a temporary table in Transact SQL

时间:2019-04-16 22:12:51

标签: sql sql-server tsql concatenation row-number

I am re-writing an export script that was run in our old flat database into our new normalized structure. In the past we had a table called Case that had three columns for owner name info - Ownername1, Ownername2 and Ownername3. Now, we have zero-to-many debtors, and instead of having one row with up to three owners we have a row for each owner. I am having to massage this into an export that will be used in an Excel spreadsheet that the client is using, but I have to "dumb down" the structure to fit it back into that flat structure. I need to grab the names of the owners of the first three rows and concatenate the first and last name. I have been playing around with (SELECT ROW_NUMBER() OVER and it looks like the solution but I can't get it to work properly for my case. I not only need to concatenate the first and last names, but I also need to coalesce them to empty string and insert the result into a temp table. In our system a Case can have multiple Debtors. The primary debtor will have an DEIsPrimary value of 1. CApKey is the key value of the case.

If I do this, using a single column I get the expected result:

(SELECT DEPhone FROM 
(SELECT ROW_NUMBER() OVER (ORDER BY DEpKey ASC) 
AS rownumber, DEPhone FROM Debtor d WHERE d.CApKey = 151490 AND d.DEIsPrimary <> 1) 
AS foo WHERE rownumber = 1)

This returns a valid phone number. When I try to expand on this, using the concatenated names like so:

(SELECT DEFirstName + ' ' + DELastName FROM 
(SELECT ROW_NUMBER() OVER (ORDER BY DEpKey ASC) 
AS rownumber, DEFIrstName + ' ' + DELastName FROM Debtor d WHERE d.CApKey = 151490 AND d.DEIsPrimary <> 1) 
AS foo WHERE rownumber = 1)

I get two errors: I'm told that DEFirstName and DELastName are invalid column names, and I'm also told that no column was specified for column 2 of foo. Is concatenation not possible in this context? I've tried aliasing the names with no luck. Here is almost what I think I need, but as you can see I haven't even gotten the COALESCE in yet. Here was my initial attempt:

UPDATE #temp SET OwnerNameTwo = (SELECT DEFirstName + ' ' + DELastName FROM 
    (SELECT ROW_NUMBER() OVER (ORDER BY DEpKey ASC) 
    AS rownumber, DEFirstName + ' ' + DELastName
    FROM Debtor d WHERE d.CApKey = #temp.CApKey AND d.DEIsPrimary <> 1) 
    AS foo WHERE rownumber = 1)

Thank you in advance for any time spent helping me with this. I really appreciate any and all feeback!

1 个答案:

答案 0 :(得分:0)

When you build a derived table you cannot access the columns of the underlying tables directly unless they appear in the list after SELECT in the outermost query of the derived table.

So

SELECT a
       FROM (SELECT a
                    FROM t) x;

works, while

SELECT b
       FROM (SELECT a
                    FROM t) x;

doesn't work even if there is a column b in t.

But in fact this goes a bit further. You can select any of the column expressions from the outermost query as in

SELECT y
       FROM (SELECT a + b y
                    FROM t) x;

But you need a name for each those columns given by expressions. Whilst some systems might automatically generate usable aliases for expressions some don't and even if they do, these aliases often aren't "nice" to read and write. So use explicit aliases.

What you cannot do here is to repeat the expression and hope that'll give you the respective value. I.e.

SELECT a + b
       FROM (SELECT a + b
                    FROM t) x;

won't work.

But the last query is what you do.

So either move the concatenation to the outer query and just list the columns in the inner query

UPDATE #temp
       SET ownernametwo = (SELECT defirstname + ' ' + delastname
                                  FROM (SELECT row_number() OVER (ORDER BY depkey ASC) rownumber,
                                               defirstname,
                                               delastname
                                               FROM debtor d
                                               WHERE d.capkey = #temp.capkey
                                                     AND d.deisprimary <> 1) foo
                                       WHERE rownumber = 1);

or keep the concatenation in the inner query alias it an us that alias in the outer query:

UPDATE #temp
       SET ownernametwo = (SELECT fullname
                                  FROM (SELECT row_number() OVER (ORDER BY depkey ASC) rownumber,
                                               defirstname + ' ' + delastname fullname
                                               FROM debtor d
                                               WHERE d.capkey = #temp.capkey
                                                     AND d.deisprimary <> 1) foo
                                       WHERE rownumber = 1);