How to create sequential numbering against two select statements that are unioned? - sql-server

I have a SQL query that is just a union between two SELECT statements. Say the result of the overall query produces 10 records. I want as part of that result set a column that is a numeric and sequential (like a primary key - 0,1,2,3, and so on). My problem is the way I have this coded, as you can see below, doesn't produce unique values (the 0 value is repeated twice, the 1 value is repeated twice, as expected, because of the union statement). How can I get the below "Transaction Sequence Number" to display 1,2,3,4,5,6,7,8,9,10? Instead of 1,2,3,4,5,1,2,3,4,5?
Here's my code (below). I will be posting a screenshot of my result set shortly - SQL Server is being incredibly slow for me right now - I hope this makes sense without a screenshot of the result set:
select top 5
'ACCT PROMORESP' as 'Transaction Identifier',
row_number() over (order by s.HL_ACCT_ID) as 'Transaction Sequence Number',
s.HL_ACCT_ID as 'HL_Acct_ID',
null as [AcctNumber],
null as [AcctType],
null as [AcctSource],
null as [DUNS_NBR],
null as [DBPLCR_CONTACT_ID],
s.CAMPAIGNCODE as [CellCode],
'-1' as [OfferCode],
case
when c.EventDate is not null then 'Click'
when c.EventDate is null then
case
when sub.status = 'unsubscribed' then 'Unsubscribe'
when sub.status = 'bounced' then 'Bounce'
when sub.status = 'held' then 'Bounce'
end
end as [ResponseType],
convert(varchar, c.EventDate, 112) as [ResponseDate],
null as [ResponseQuantity],
null as [ResponseValue],
'Email' as [ResponseChannel],
null as [Cookie ID],
null as [IP address],
null as [Device ID],
null as [CUSTOM_TEXT_01],
null as [CUSTOM_TEXT_02],
null as [CUSTOM_TEXT_03],
null as [CUSTOM_TEXT_04],
null as [CUSTOM_TEXT_05]
from cXXXXXXX.sendlog s with (nolock)
inner join cXXXXXXX._subscribers sub with (nolock) on sub.SubscriberKey = s.Email
left join cXXXXXXX._click c with (nolock) on c.JobID = s.JobID and c.SubscriberKey = s.Email
where c.EventDate is not null or (c.EventDate is null and (sub.status = 'unsubscribed' or sub.status = 'bounced' or sub.status = 'held')) and c.isunique = 1
union all
select top 5
'ACCT PROMORESP' as 'Transaction Identifier',
(row_number() over (order by s.HL_ACCT_ID)) + 1 as 'Transaction Sequence Number',
s.HL_ACCT_ID as 'HL_Acct_ID',
null as [AcctNumber],
null as [AcctType],
null as [AcctSource],
null as [DUNS_NBR],
null as [DBPLCR_CONTACT_ID],
s.CAMPAIGNCODE as [CellCode],
'-1' as [OfferCode],
case
when o.EventDate is not null then 'Message Open'
when o.EventDate is null then
case
when sub.status = 'unsubscribed' then 'Unsubscribe'
when sub.status = 'bounced' then 'Bounce'
when sub.status = 'held' then 'Bounce'
end
end as [ResponseType],
convert(varchar, o.EventDate, 112) as [ResponseDate],
null as [ResponseQuantity],
null as [ResponseValue],
'Email' as [ResponseChannel],
null as [Cookie ID],
null as [IP address],
null as [Device ID],
null as [CUSTOM_TEXT_01],
null as [CUSTOM_TEXT_02],
null as [CUSTOM_TEXT_03],
null as [CUSTOM_TEXT_04],
null as [CUSTOM_TEXT_05]
from cXXXXXXX.sendlog s with (nolock)
inner join cXXXXXXX._subscribers sub with (nolock) on sub.SubscriberKey = s.Email
left join cXXXXXXX._open o with (nolock) on o.JobID = s.JobID and o.SubscriberKey = s.Email
where o.EventDate is not null or (o.EventDate is null and (sub.status = 'unsubscribed' or sub.status = 'bounced' or sub.status = 'held')) and o.isunique = 1

You can enclose your sql in a common table expression and then number them:
;WITH CTE AS(your sql...)
SELECT *,
(row_number() over (order by HL_ACCT_ID)) + 1 as 'Transaction Sequence Number'
FROM CTE
You have to make sure you have unique column names in the cte. Also, if you are using this sql statement with other statements, make sure you add a ';' before it or end the previous statement with a ';'.

Try using this.
SELECT ROW_NUMBER() OVER(ORDER BY DATA.HL_ACCT_ID),DATA.* FROM
(your query here...)DATA

Related

Assignment to use case statement and group by with an aggregate

SELECT count(AccountNumber),
CustomerType = CASE WHEN personid IS NOT NULL AND StoreID IS NOT NULL
THEN 'Store with contact'
when personid IS NOT NULL AND StoreID IS NULL
THEN 'store'
when personid IS NULL AND StoreID IS NOT NULL
THEN 'Person'
ELSE 'Error'
end
FROM Sales.Customer AS c
LEFT JOIN Person.Person AS P
ON c.PersonID = p.BusinessEntityID
LEFT JOIN Sales.Store ON
c.StoreID = Store.BusinessEntityID
Group by CASE WHEN personid IS NOT NULL AND StoreID IS NOT NULL
THEN concat(store.name,'-',CONCAT(lastname,',',firstname,'',CASE WHEN middleName IS
NULL
THEN '' WHEN len(middlename) = 1 THEN concat(middlename,'.') when len(middlename)>1
then middlename ELSE 'Error'
end)) when personid IS NOT NULL AND StoreID IS NULL
THEN Store.Name
when personid IS NULL AND StoreID IS NOT NULL
THEN CONCAT(lastname,',',firstname,'',CASE WHEN middleName IS NULL
THEN ''
WHEN len(middlename) = 1
THEN concat(middlename,'.')
when len(middlename)>1
then middlename
ELSE 'Error'
End
Not clear what that bottom case is doing, but you can either replicate the CASE in the group by or even use a CROSS APPLY to reduce duplication
SELECT count(AccountNumber)
,CustomerType = CASE WHEN personid IS NOT NULL AND StoreID IS NOT NULL THEN 'Store with contact'
when personid IS NOT NULL AND StoreID IS NULL THEN 'store'
when personid IS NULL AND StoreID IS NOT NULL THEN 'Person'
ELSE 'Error'
end
FROM Sales.Customer AS c
LEFT JOIN Person.Person AS P ON c.PersonID = p.BusinessEntityID
LEFT JOIN Sales.Store ON c.StoreID = Store.BusinessEntityID
Group By CASE WHEN personid IS NOT NULL AND StoreID IS NOT NULL THEN 'Store with contact'
when personid IS NOT NULL AND StoreID IS NULL THEN 'store'
when personid IS NULL AND StoreID IS NOT NULL THEN 'Person'
ELSE 'Error'
end
Or with a CROSS APPLY
SELECT count(AccountNumber)
,CustomerType
FROM Sales.Customer AS c
LEFT JOIN Person.Person AS P ON c.PersonID = p.BusinessEntityID
LEFT JOIN Sales.Store ON c.StoreID = Store.BusinessEntityID
Cross Apply ( values ( CASE WHEN personid IS NOT NULL AND StoreID IS NOT NULL THEN 'Store with contact'
when personid IS NOT NULL AND StoreID IS NULL THEN 'store'
when personid IS NULL AND StoreID IS NOT NULL THEN 'Person'
ELSE 'Error'
end
) ) D(CustomerType)
Group By CustomerType

is it possible to improve the "contains" filter for a view?

I have a view like this in SQL Server:
ALTER VIEW [dbo].[myUsers]
AS
SELECT
T1.*,
STRING_AGG(gr.Name, '; ') WITHIN GROUP (ORDER BY gr.Name) AS MemberOf
FROM
(SELECT
mu.Id,
CASE
WHEN iu.ObjectGuid IS NULL
THEN u.Username
ELSE iu.SAMAccountName
END AS Username,
CASE
WHEN iu.ObjectGuid IS NULL
THEN u.FirstName
ELSE iu.GivenName
END AS FirstName,
CASE
WHEN iu.ObjectGuid IS NULL
THEN u.LastName
ELSE iu.LastName
END AS LastName,
CASE
WHEN iu.ObjectGuid IS NULL
THEN u.Email
ELSE iu.Email
END AS Email,
CASE
WHEN iu.ObjectGuid IS NULL
THEN u.Phone
ELSE iu.Telephone
END AS Phone,
CASE
WHEN iu.ObjectGuid IS NULL
THEN u.Mobile
ELSE iu.Mobile
END AS Mobile,
CASE
WHEN iu.ObjectGuid IS NULL
THEN u.CompanyCode
ELSE co.Code
END AS CompanyCode,
co.Name,
CASE
WHEN iu.ObjectGuid IS NULL
THEN 0
ELSE 1
END AS IsNotMaster
FROM
MasterUsers mu
LEFT JOIN
Users u ON u.Id = mu.UsersId
LEFT JOIN
InternalUsers iu ON iu.ObjectGuid = mu.ObjectsGUID
LEFT JOIN
Companies co ON co.name = iu.company
WHERE
iu.ObjectGuid IS NULL OR iu.ModifiedStatus < 100) AS T1
LEFT JOIN
MasterUsers mu ON mu.Username = T1.Email
LEFT JOIN
UsersGroups ug ON ug.MasterUsersId = mu.Id
LEFT JOIN
Groups gr ON gr.Id = ug.GroupsId
GROUP BY
t1.id, T1.Username, T1.FirstName, T1.LastName, T1.Email,
T1.Phone, T1.Mobile, T1.CompanyCode, T1.Name, T1.IsNotMaster
When I run it and filter by Username and equal, it's pretty fast (a few ms):
SELECT [Id]
,[Username]
,[FirstName]
,[LastName]
,[Email]
,[Phone]
,[Mobile]
,[CompanyCode]
,[Name]
,[IsNotMaster]
,[MemberOf]
FROM [dbo].[myUsers]
WHERE Username = 'testuser'
but if I use contains on Username, it become very slow (such as 3/4 seconds):
SELECT [Id]
,[Username]
,[FirstName]
,[LastName]
,[Email]
,[Phone]
,[Mobile]
,[CompanyCode]
,[Name]
,[IsNotMaster]
,[MemberOf]
FROM [dbo].[myUsers]
WHERE Username LIKE '%testuser%'
Where could I improve the query, in your opinion? Are indexes on the view is possible?
I could change the view itself or add/edit indexes, but not add the filtering (i.e. Username and where) inside it (since I call it wherever, for various purpose, and must be generic).

SUM all returned values from the CASE clause statement

I have the following query. And need to sum all returned by the query "distinct case" values withing a row populated in another column "TotalDepartmentsCount"
;WITH CTE
AS
(
Select t.ID As [CTE_ID]
,count(distinct case when e.Department='M' then t.ID else null end) as M_Marketing
,count(distinct case when e.Department='S' then t.ID else null end) as S_Sales
,count(distinct case when e.Department='U' then t.ID else null end) as U_Utilization
,count(distinct case when e.Department=' ' then t.ID else null end) as No_NoDepartment
From dbo.Table t (nolock)
Left Join dbo.ClearedEmployee ce (nolock) ON t.ID = ce.building_fk
Join dbo.Employee e (nolock) ON ce.employee_fk = e.employee_pk
Group By t.ID
)
Select *, t.ID
From CTE c (nolock)
FULL JOIN dbo.Table t (nolock) ON t.ID=c.[CTE_ID]
Order By t.ID ASC;
To do it I added this code in the select list:
sum(cast(e.Department as int)) As TotalDepartmentsCount
But this does not sum up correctly (see screenshot below). Please advise.
This is how I want to have my output (see the TotalDepartmentsCount table)
Why not just add the columns together once you've calculated them? e.g.:
;WITH CTE
AS
(
Select t.ID As [CTE_ID]
,count(distinct case when e.Department='M' then t.ID else null end) as M_Marketing
,count(distinct case when e.Department='S' then t.ID else null end) as S_Sales
,count(distinct case when e.Department='U' then t.ID else null end) as U_Utilization
,count(distinct case when e.Department=' ' then t.ID else null end) as No_NoDepartment
From dbo.Table t (nolock)
Left Join dbo.ClearedEmployee ce (nolock) ON t.ID = ce.building_fk
Join dbo.Employee e (nolock) ON ce.employee_fk = e.employee_pk
Group By t.ID
)
Select *
, t.ID
, isnull(M_Marketing, 0) + isnull(S_Sales, 0) + isnull(U_Utilization, 0) + isnull(No_NoDepartment, 0) as TotalDepartments
From CTE c (nolock)
FULL JOIN dbo.Table t (nolock) ON t.ID=c.[CTE_ID]
Order By t.ID ASC;
Your CTE currently computes 4 counts by filtering based on department. What you want is a 5th count that includes all rows (e.g., no filtering). So you should be able to add that column to your CTE like so:
;WITH CTE
AS
(
Select t.ID As [CTE_ID]
,count(distinct case when e.Department='M' then t.ID else null end) as M_Marketing
,count(distinct case when e.Department='S' then t.ID else null end) as S_Sales
,count(distinct case when e.Department='U' then t.ID else null end) as U_Utilization
,count(distinct case when e.Department=' ' then t.ID else null end) as No_NoDepartment
,count(distinct t.ID) as TotalDepartmentsCount
From dbo.Table t (nolock)
Left Join dbo.ClearedEmployee ce (nolock) ON t.ID = ce.building_fk
Join dbo.Employee e (nolock) ON ce.employee_fk = e.employee_pk
Group By t.ID
)
The above will work as long as the Department column only contains the four specific values used in distinct cases ('M', 'S', 'U', and ' '). If you can have other Department values that you need to ignore, you can change the TotalDepartmentsCount column in your CTE to be calculated like this:
,count(distinct case when e.Department in ('M', 'S', 'U', ' ') then t.ID else null end) as TotalDepartmentsCount
Or you can simply compute the sum of the four columns in your final query, like so:
Select c.*
, (M_Marketing + S_Sales + U_Utilization + No_NoDepartment) as TotalDepartmentsCount
, t.ID
From CTE c (nolock)

SQL query is running, but stopped producing incremental results

I have the below query running in SQL Server. In a nutshell, I have 3 somewhat identical queries "unioned". When I start the query, it runs and produces incremental results in the Results pane. But, once it reaches 264,619 records (first 5 minutes), it just stops producing results, yet the query is running and has been running for 30 minutes. Any ideas why this is happening? I understand the query below is kind of long/semi-complex, so my apologies, I couldn't make it any simpler (I'm hoping someone might be able to point me in a direction that I would be able to make the query below a little simpler). Below the query is a screenshot of the results pane. I'm wondering if the query is deadlocked somewhere or running into an infinite loop/etc.:
select
Q1.[Transaction Identifier],
row_number() over (order by (select 1)) as 'Transaction Sequence Number',
Q1.HL_Acct_ID,
Q1.AcctNumber,
Q1.AcctType,
Q1.AcctSource,
Q1.DUNS_NBR,
Q1.DBPLCR_CONTACT_ID,
Q1.CellCode,
Q1.OfferCode,
Q1.ResponseType,
Q1.ResponseDate,
Q1.ResponseQuantity,
Q1.ResponseValue,
Q1.ResponseChannel,
Q1.[Cookie ID],
Q1.[IP Address],
Q1.[Device ID],
Q1.[CUSTOM_TEXT_01],
Q1.[CUSTOM_TEXT_02],
Q1.[CUSTOM_TEXT_03],
Q1.[CUSTOM_TEXT_04],
Q1.[CUSTOM_TEXT_05]
from
(
select
'ACCT PROMORESP' as 'Transaction Identifier',
s.HL_ACCT_ID as 'HL_Acct_ID',
null as [AcctNumber],
null as [AcctType],
null as [AcctSource],
null as [DUNS_NBR],
null as [DBPLCR_CONTACT_ID],
s.CELLCODE as [CellCode],
case
when c.URL is not null then c.URL
else '-1'
end as [OfferCode],
case
when c.EventDate is not null then 'Click'
when c.EventDate is null then
case
when sub.status = 'unsubscribed' then 'Unsubscribe'
when sub.status = 'bounced' then 'Bounce'
when sub.status = 'held' then 'Bounce'
end
end as [ResponseType],
convert(varchar, c.EventDate, 112) as [ResponseDate],
null as [ResponseQuantity],
null as [ResponseValue],
'Email' as [ResponseChannel],
null as [Cookie ID],
null as [IP address],
null as [Device ID],
null as [CUSTOM_TEXT_01],
null as [CUSTOM_TEXT_02],
null as [CUSTOM_TEXT_03],
null as [CUSTOM_TEXT_04],
null as [CUSTOM_TEXT_05]
from C1111111.[151222_Hostess Ensemble] s with (nolock)
inner join C1111111._subscribers sub with (nolock) on sub.SubscriberKey = s.Email
left join C1111111._click c with (nolock) on c.JobID in
(
select j.fkJobId from tblJobs_Lists j with (nolock)
inner join customobject c with (nolock) on j.customobjectid = c.customobjectid
where c.memberid = 1111111
and c.customobjectname like '151222_Hostess Ensemble'
)
and c.SubscriberKey = s.Email
where c.EventDate is not null or (c.EventDate is null and (sub.status in ('unsubscribed','bounced','held'))) and c.isunique = 1
union all
select
'ACCT PROMORESP' as 'Transaction Identifier',
s.HL_ACCT_ID as 'HL_Acct_ID',
null as [AcctNumber],
null as [AcctType],
null as [AcctSource],
null as [DUNS_NBR],
null as [DBPLCR_CONTACT_ID],
s.CELLCODE as [CellCode],
'-1' as [OfferCode],
case
when o.EventDate is not null then 'Message Open'
when o.EventDate is null then
case
when sub.status = 'unsubscribed' then 'Unsubscribe'
when sub.status = 'bounced' then 'Bounce'
when sub.status = 'held' then 'Bounce'
end
end as [ResponseType],
convert(varchar, o.EventDate, 112) as [ResponseDate],
null as [ResponseQuantity],
null as [ResponseValue],
'Email' as [ResponseChannel],
null as [Cookie ID],
null as [IP address],
null as [Device ID],
null as [CUSTOM_TEXT_01],
null as [CUSTOM_TEXT_02],
null as [CUSTOM_TEXT_03],
null as [CUSTOM_TEXT_04],
null as [CUSTOM_TEXT_05]
from C1111111.[151222_Hostess Ensemble] s with (nolock)
inner join C1111111._subscribers sub with (nolock) on sub.SubscriberKey = s.Email
left join C1111111._open o with (nolock) on o.JobID in
(
select j.fkJobId from tblJobs_Lists j with (nolock)
inner join customobject c with (nolock) on j.customobjectid = c.customobjectid
where c.memberid = 1111111
and c.customobjectname like '151222_Hostess Ensemble'
)
and o.SubscriberKey = s.Email
where o.EventDate is not null or (o.EventDate is null and (sub.status in ('unsubscribed','bounced','held'))) and o.isunique = 1
UNION ALL
select
'ACCT PROMORESP' as 'Transaction Identifier',
s.HL_ACCT_ID as 'HL_Acct_ID',
null as [AcctNumber],
null as [AcctType],
null as [AcctSource],
null as [DUNS_NBR],
null as [DBPLCR_CONTACT_ID],
s.CELLCODE as [CellCode],
'-1' as [OfferCode],
null as [ResponseType],
convert(varchar, o.EventDate, 112) as [ResponseDate],
null as [ResponseQuantity],
null as [ResponseValue],
'Email' as [ResponseChannel],
null as [Cookie ID],
null as [IP address],
null as [Device ID],
null as [CUSTOM_TEXT_01],
null as [CUSTOM_TEXT_02],
null as [CUSTOM_TEXT_03],
null as [CUSTOM_TEXT_04],
null as [CUSTOM_TEXT_05]
from C1111111.[151222_Hostess Ensemble] s with (nolock)
inner join C1111111._subscribers sub with (nolock) on sub.SubscriberKey = s.Email
left join C1111111._open o with (nolock) on o.JobID in
(
select j.fkJobId from tblJobs_Lists j with (nolock)
inner join customobject c with (nolock) on j.customobjectid = c.customobjectid
where c.memberid = 1111111
and c.customobjectname like '151222_Hostess Ensemble'
)
left join C1111111._click cl with (nolock) on o.JobID in
(
select j.fkJobId from tblJobs_Lists j with (nolock)
inner join customobject c with (nolock) on j.customobjectid = c.customobjectid
where c.memberid = 1111111
and c.customobjectname like '151222_Hostess Ensemble'
)
and cl.SubscriberKey = s.Email
where cl.EventDate is null and o.EventDate is null and sub.status not in ('unsubscribed','bounced','held')) as Q1
Without the table definitions I can't verify that this is correct, but this would be my take at a simplification of the above, with an assumption about two fixes in the join conditions:
set transaction isolation level read uncommitted;
WITH JobIDs AS
(
select j.fkJobId from tblJobs_Lists j
inner join customobject c on j.customobjectid = c.customobjectid
where c.memberid = 1111111
and c.customobjectname = '151222_Hostess Ensemble'
)
select
'ACCT PROMORESP' as 'Transaction Identifier',
row_number() over (order by (select 1)) as 'Transaction Sequence Number',
s.HL_ACCT_ID as 'HL_Acct_ID',
null as [AcctNumber],
null as [AcctType],
null as [AcctSource],
null as [DUNS_NBR],
null as [DBPLCR_CONTACT_ID],
s.CELLCODE as [CellCode],
X.OfferCode,
X.ResponseType,
convert(varchar, X.EventDate, 112) as [ResponseDate],
null as [ResponseQuantity],
null as [ResponseValue],
'Email' as [ResponseChannel],
null as [Cookie ID],
null as [IP address],
null as [Device ID],
null as [CUSTOM_TEXT_01],
null as [CUSTOM_TEXT_02],
null as [CUSTOM_TEXT_03],
null as [CUSTOM_TEXT_04],
null as [CUSTOM_TEXT_05]
from
(
SELECT
s.HL_ACCT_ID,
s.CELLCODE,
s.Email,
case sub.status
when 'unsubscribed' then 'Unsubscribe'
when 'bounced' then 'Bounce'
when 'held' then 'Bounce'
end as [ResponseType],
sub.status
from C1111111.[151222_Hostess Ensemble] s
inner join C1111111._subscribers sub on sub.SubscriberKey = s.Email
) as s
left join C1111111._open o on o.JobID in (select fkJobId from JobIDs)
-- DON'T YOU NEED A "and o.SubscriberKey = s.Email" HERE?
and o.SubscriberKey = s.Email
left join C1111111._click cl on cl.JobID in (select fkJobId from JobIDs)
-- LOOK ABOVE, was "o.JobID", **REALLY**
and cl.SubscriberKey = s.Email
cross apply (
select
'-1' as [OfferCode],
case
when o.EventDate is not null then 'Message Open'
else s.[ResponseType]
end as [ResponseType],
o.EventDate
where o.EventDate is not null or (o.EventDate is null and (s.status in ('unsubscribed','bounced','held'))) and o.isunique = 1
UNION ALL
select
isnull(cl.URL,'-1') as [OfferCode],
case
when c.EventDate is not null then 'Click'
else s.[ResponseType]
end as [ResponseType],
cl.EventDate
where cl.EventDate is not null or (cl.EventDate is null and (s.status in ('unsubscribed','bounced','held'))) and cl.isunique = 1
union all
select
'-1' as [OfferCode],
NULL AS [ResponseType],
null as EventDate
where cl.EventDate is null and o.EventDate is null and s.status not in ('unsubscribed','bounced','held')
) AS X

SQL : updating a column based on other columns

SQL Server:
I have a following table.
ID Type1 Type2 error
_____________________
1 P107 0057 NULL
2 P101 1142 NULL
3 P107 1142 NULL
now here I have to check type1 column in table 1 if data exists, type2 in table2.
Lets assume that P101 exists in table1 and 0057 exist in table2.
Table1 have many columns but we are checking for col = 'type1' same is true for table2 just checking col = 'type2'.
So, error generated should be like:
ID Type1 Type2 error
_____________________
1 P107 0057 <type1 invalid>
2 P101 1142 <type2 invalid>
3 P107 1142 <type1 invalid> + <type2 invalid>
PS: There might be other messages that are already existing in error column, we dont want to delete those messages but to add the new messages if any.
For example I might have the table like :
ID Type1 Type2 error
_____________________
1 P107 0057 NULL
2 P101 1142 <duplicate>
3 P107 1142 NULL
now, I want to add the new error in id = 2 like,
ID Type1 Type2 error
_____________________
1 P107 0057 <type1 invalid>
2 P101 1142 <duplicate> + <type2 invalid>
3 P107 1142 <type1 invalid> + <type2 invalid>
Any help will be appreciated !! Thanks in advance .
If the following produces the results you want:
SELECT t.ID, t.Type1, t.Type2,
error = COALESCE(t.error + ' + ', '') + CASE
WHEN t1.type1 IS NULL AND t2.type2 IS NULL
THEN '<type1 invalid> + <type2 invalid>'
WHEN t1.type1 IS NULL THEN '<type1 invalid>'
WHEN t2.type2 IS NULL THEN '<type2 invalid>'
ELSE t.error END
FROM dbo.table AS t
LEFT OUTER JOIN dbo.Table1 AS t1
ON t.Type1 = t1.Type1
LEFT OUTER JOIN dbo.Table2 AS t2
ON t.Type2 = t2.Type2
WHERE t1.Type1 IS NULL OR t2.Type2 IS NULL;
Then you can run this update statement:
UPDATE t
SET error = COALESCE(t.error + ' + ', '') + CASE
WHEN t1.type1 IS NULL AND t2.type2 IS NULL
THEN '<type1 invalid> + <type2 invalid>'
WHEN t1.type1 IS NULL THEN '<type1 invalid>'
WHEN t2.type2 IS NULL THEN '<type2 invalid>'
ELSE t.error END
FROM dbo.table AS t
LEFT OUTER JOIN dbo.Table1 AS t1
ON t.Type1 = t1.Type1
LEFT OUTER JOIN dbo.Table2 AS t2
ON t.Type2 = t2.Type2
WHERE t1.Type1 IS NULL OR t2.Type2 IS NULL;
Added where clause to account for new information added to the question as an afterthought. Assuming that the column is NULL when there isn't yet an error message.
EDIT updated for yet MORE new requirements.
EDIT and again. Is there an echo?
Here's a repro you can run in tempdb to see that, no, you don't need to use variables and no, you don't need to write 10! (yes, I know what factorial means) case expressions to get this done.
Core table:
USE tempdb;
GO
CREATE TABLE dbo.[table]
(
ID INT,
Type1 VARCHAR(4),
Type2 VARCHAR(4),
Type3 VARCHAR(4),
Type4 VARCHAR(4),
Type5 VARCHAR(4),
Type6 VARCHAR(4),
Type7 VARCHAR(4),
Type8 VARCHAR(4),
Type9 VARCHAR(4),
Type10 VARCHAR(4),
error VARCHAR(MAX)
);
GO
Some rows:
INSERT dbo.[table] SELECT -- this will yield type 1 invalid:
1,'P107','0057','x', 'x','x','x','x', 'x','x','x',NULL
UNION ALL SELECT -- this will yield type 2 invalid:
2,'P101','1142','x', 'x','x','x','x', 'x','x','x','<duplicate>'
UNION ALL SELECT -- this will yield type 1 + type 2 invalid:
3,'P107','1142','x', 'x','x','x','x', 'x','x','x',NULL
UNION ALL SELECT -- no problems here:
4,'x', 'x', 'x205','x','x','x','y676','x','x','x',NULL
UNION ALL SELECT -- this will yield type 3 invalid:
5,'x', 'x', 'x206','x','x','x','y676','x','x','x','<other>';
Related tables and rows:
CREATE TABLE dbo.Table1 (Type1 VARCHAR(4));
CREATE TABLE dbo.Table2 (Type2 VARCHAR(4));
CREATE TABLE dbo.Table3 (Type3 VARCHAR(4));
CREATE TABLE dbo.Table4 (Type4 VARCHAR(4));
CREATE TABLE dbo.Table5 (Type5 VARCHAR(4));
CREATE TABLE dbo.Table6 (Type6 VARCHAR(4));
CREATE TABLE dbo.Table7 (Type7 VARCHAR(4));
CREATE TABLE dbo.Table8 (Type8 VARCHAR(4));
CREATE TABLE dbo.Table9 (Type9 VARCHAR(4));
CREATE TABLE dbo.Table10(Type10 VARCHAR(4));
INSERT dbo.Table1 SELECT 'P101';
INSERT dbo.Table2 SELECT '0057';
INSERT dbo.Table3 SELECT 'x205';
INSERT dbo.Table7 SELECT 'y676';
-- I know you won't have x's but I assume you'll have
-- valid data most of the time.
INSERT dbo.Table1 SELECT 'x';
INSERT dbo.Table2 SELECT 'x';
INSERT dbo.Table3 SELECT 'x';
INSERT dbo.Table4 SELECT 'x';
INSERT dbo.Table5 SELECT 'x';
INSERT dbo.Table6 SELECT 'x';
INSERT dbo.Table7 SELECT 'x';
INSERT dbo.Table8 SELECT 'x';
INSERT dbo.Table9 SELECT 'x';
INSERT dbo.Table10 SELECT 'x';
Let's make sure the table looks right:
SELECT * FROM dbo.[table];
Now, a single statement, only 10 case expressions, not 10!:
UPDATE t SET error = REPLACE(COALESCE(t.error, '')
+ CASE WHEN t1.type1 IS NULL THEN '<type1 invalid>' ELSE '' END
+ CASE WHEN t2.type2 IS NULL THEN '<type2 invalid>' ELSE '' END
+ CASE WHEN t3.type3 IS NULL THEN '<type3 invalid>' ELSE '' END
+ CASE WHEN t4.type4 IS NULL THEN '<type4 invalid>' ELSE '' END
+ CASE WHEN t5.type5 IS NULL THEN '<type5 invalid>' ELSE '' END
+ CASE WHEN t6.type6 IS NULL THEN '<type6 invalid>' ELSE '' END
+ CASE WHEN t7.type7 IS NULL THEN '<type7 invalid>' ELSE '' END
+ CASE WHEN t8.type8 IS NULL THEN '<type8 invalid>' ELSE '' END
+ CASE WHEN t9.type9 IS NULL THEN '<type9 invalid>' ELSE '' END
+ CASE WHEN t10.type10 IS NULL THEN '<type10 invalid>' ELSE '' END, '><', '> + <')
FROM dbo.[table] AS t
LEFT OUTER JOIN dbo.Table1 AS t1 ON t.Type1 = t1.Type1
LEFT OUTER JOIN dbo.Table2 AS t2 ON t.Type2 = t2.Type2
LEFT OUTER JOIN dbo.Table3 AS t3 ON t.Type3 = t3.Type3
LEFT OUTER JOIN dbo.Table4 AS t4 ON t.Type4 = t4.Type4
LEFT OUTER JOIN dbo.Table5 AS t5 ON t.Type5 = t5.Type5
LEFT OUTER JOIN dbo.Table6 AS t6 ON t.Type6 = t6.Type6
LEFT OUTER JOIN dbo.Table7 AS t7 ON t.Type7 = t7.Type7
LEFT OUTER JOIN dbo.Table8 AS t8 ON t.Type8 = t8.Type8
LEFT OUTER JOIN dbo.Table9 AS t9 ON t.Type9 = t9.Type9
LEFT OUTER JOIN dbo.Table10 AS t10 ON t.Type10 = t10.Type10
WHERE t1.Type1 IS NULL
OR t2.Type2 IS NULL
OR t3.Type3 IS NULL
OR t4.Type4 IS NULL
OR t5.Type5 IS NULL
OR t6.Type6 IS NULL
OR t7.Type7 IS NULL
OR t8.Type8 IS NULL
OR t9.Type9 IS NULL
OR t10.Type10 IS NULL;
GO
Once the update has run, let's check and make sure the right rows have been updated:
SELECT * FROM dbo.[table];
GO
And cleanup:
DROP TABLE dbo.[table],
dbo.Table1, dbo.Table2, dbo.Table3, dbo.Table4, dbo.Table5,
dbo.Table6, dbo.Table7, dbo.Table8, dbo.Table9, dbo.Table10;
UPDATE yt
SET error = CASE WHEN t1.Type1 IS NULL AND t2.Type2 IS NULL THEN '<type1 invalid> + <type2 invalid>'
WHEN t1.Type1 IS NULL THEN '<type1 invalid>'
WHEN t2.Type2 IS NULL THEN '<type2 invalid>'
END
FROM YourTable yt
LEFT JOIN table1 t1
ON yt.Type1 = t1.Type1
LEFT JOIN table2 t2
ON yt.Type2 = t2.Type2
WHERE t1.Type1 IS NULL
OR t2.Type2 IS NULL;

Resources