Select only the top 1 value from a column in a table that I'm joining? - sql

So below is the query, how can I store only the top 1 "agencyID" into DCA.AgencyID? I know that the way the query below is structured now it would select all the "agencyID" values and not just the top 1.
SELECT AP.ID
,DCA.AgencyID as agencyID --How to store select top 1?
,replace(LTRIM(RTRIM(AP.UserNameWebsite)), '\', '') AS username
,replace(LTRIM(RTRIM(AP.FirstName)), '\', '') + N' ' + replace(LTRIM(RTRIM(AP.LastName)), '\', '') AS fullName
,LTRIM(RTRIM(AP.EmailAddress)) AS email
,LTRIM(RTRIM(AP.Phone1)) AS phone1
,LTRIM(RTRIM(AP.Phone2)) AS phone2
,LTRIM(RTRIM(AP.GreenSolution)) AS greenSolution
,CASE
WHEN UserType = 'AM'
THEN 1
ELSE 0
END AS producer
FROM DEV01_DataExchange.[DuckCreek].[fpmAgentsProfile] AP
Inner Join [DUCKCREEK_DEV].[DEV01_DuckCreek_Consolidated].[dbo].Agency DCA
on AP.AgencyID = DCA.Reference
WHERE TransType = 'A' AND DC_LastModifiedDate IS NULL AND DCA.Reference is NOT NULL

Your question is a bit vague, but the answer is cross apply:
FROM DEV01_DataExchange.[DuckCreek].[fpmAgentsProfile] AP CROSS APPLY
(SELECT TOP (1) DCA.*
FROM [DUCKCREEK_DEV].[DEV01_DuckCreek_Consolidated].[dbo].Agency DCA
WHERE AP.AgencyID = DCA.Reference
) DCA
WHERE TransType = 'A' AND DC_LastModifiedDate IS NULL AND DCA.Reference is NOT NULL;
Normally an ORDER BY clause would be used. Perhaps ORDER BY DCA.AgencyID DESC? However, if there is a column called AgencyID, I'm surprised it is not being used for the alignment to AP.
Also, some of the WHERE conditions might belong in the subquery.

You can use a Cross Apply instead of the Join:
SELECT AP.ID
,DCA.AgencyID as agencyID
,replace(LTRIM(RTRIM(AP.UserNameWebsite)), '\', '') AS username
,replace(LTRIM(RTRIM(AP.FirstName)), '\', '') + N' ' + replace(LTRIM(RTRIM(AP.LastName)), '\', '') AS fullName
,LTRIM(RTRIM(AP.EmailAddress)) AS email
,LTRIM(RTRIM(AP.Phone1)) AS phone1
,LTRIM(RTRIM(AP.Phone2)) AS phone2
,LTRIM(RTRIM(AP.GreenSolution)) AS greenSolution
,CASE
WHEN UserType = 'AM'
THEN 1
ELSE 0
END AS producer
FROM DEV01_DataExchange.[DuckCreek].[fpmAgentsProfile] AP
Cross Apply
(
Select top 1 AG.*
From [DUCKCREEK_DEV].[DEV01_DuckCreek_Consolidated].[dbo].Agency AG
where AG.Reference = AP.AgencyID
) DCA
WHERE TransType = 'A' AND DC_LastModifiedDate IS NULL AND DCA.Reference is NOT NULL

Related

One column into multiple columns by type, plus concatenating multiples

I have a table like this:
Customer
Number
Type
1
234.567.8910
1
1
234.234.2345
2
2
234.567.5555
1
2
151.513.5464
1
3
845.846.8486
3
I am trying to include this information with information from another table (say... address), but in separate columns by type, and I want to concatenate values that are of the same type so that the return looks like this:
Customer
Cell
Home
Work
1
234.567.8910
234.234.2345
NULL
2
234.567.5555 & 151.513.5464
NULL
NULL
3
NULL
NULL
845.846.8486
When I use the STRING_AGG function, it appends the value for each line of that customer - even if it would be null when the function isn't applied, so the customer 1 has both the cell and home numbers repeated twice.
The only workaround I can find is to select each column in a subquery and join them together. Is that the only option?
Try with FOR XML and PATH.
Query
select [Customer],
stuff((
select distinct ',' + [Number]
from [your_table_name]
where [Customer] = a.[Customer]
and [Type] = 1
for xml path (''))
, 1, 1, '') as [Cell],
stuff((
select distinct ',' + [Number]
from [your_table_name]
where [Customer] = a.[Customer]
and [Type] = 2
for xml path (''))
, 1, 1, '') as [Home],
stuff((
select distinct ',' + [Number]
from [your_table_name]
where [Customer] = a.[Customer]
and [Type] = 3
for xml path (''))
, 1, 1, '') as [Work]
from [your_table_name] as a
group by [Customer];
You need conditional aggregation:
SELECT
Customer,
STRING_AGG(CASE WHEN Type = 1 THEN Number END, ' & ') Cell,
STRING_AGG(CASE WHEN Type = 2 THEN Number END, ' & ') Home,
STRING_AGG(CASE WHEN Type = 3 THEN Number END, ' & ') Work
From table

Concatenate first name, last name and middle name with comma

I want to concatenate 3 columns in SQL server as below:
MAX(LTRIM(RTRIM((ISNULL(LastName,'') +
', ' +
ISNULL(FirstName,'') +
', ' +
ISNULL(MiddleName,''))))) AS FullName
I have used value of this column in SELECT clause as:
MAX(FullName) AS FullName,
I would like to handle NULL values, in case all 3 last name, middle name and first name are BLANK or NULL. The query used above will show " , , " in case all 3 columns are NULL or BLANK. But I want to show "N/A" in such case.
Thanks in advance.
You could use a CASE expression:
SELECT MAX(CASE WHEN ISNULL(FirstName, '') = '' AND
ISNULL(MiddleName, '') = '' AND
ISNULL(LastName, '') = ''
THEN 'N/A'
ELSE LTRIM(RTRIM((ISNULL(LastName,'') + ', ' +
ISNULL(FirstName,'') + ', ' +
ISNULL(MiddleName,''))))
END) AS FullName
FROM yourTable
...
Check with COALESCE and then CASE Statement:
Declare #FirstName VARCHAR(50)='',#MiddleName VARCHAR(50),#LastName VARCHAR(50)
SELECT
CASE WHEN ISNULL(COALESCE(#FirstName,#MiddleName,#LastName),'')<>''
THEN ISNULL(#FirstName,'')+',' +ISNULL(#MiddleName,'')+','+ISNULL(#LastName,'')
ELSE 'N/A' END AS FullName
Use Concat like below this will do implicit conversion. So no need to use ISNULL.
select isnull(MAX(LTRIM(RTRIM((concat(LastName,
', ' ,
FirstName,
', ' ,
MiddleName,''))))) ,'n/a')AS FullName from table
The below method may seem quite complicated, but it does make adding or removing columns much simpler, and for all its perceived complexity it isn't actually doing that much under the hood, so doesn't add much overhead.
The first step is to unpivot each of your columns to rows with a common column name, so you would turn
FirstName MiddleName LastName
------------------------------------
A NULL C
Into
Name
------
A
NULL
C
Using CROSS APPLY along with the table value constructor VALUES
SELECT x.Name
FROM (VALUES ('A', NULL,'C')) AS t (FirstName, MiddleName, LastName)
CROSS APPLY (VALUES (1, t.FirstName), (2, t.MiddleName), (3, t.LastName)) x (SortOrder, Name)
ORDER BY x.SortOrder
Then you can remove NULLs and blanks with WHERE ISNULL(Name, '') <> '', then you only have valid data to concatenate together which you can do using SQL Server's XML Extensions. So you end up with a full query like:
WITH TestData AS
( SELECT *
FROM (VALUES ('A'), (NULL)) AS f (FirstName)
CROSS JOIN (VALUES ('B'), (NULL)) AS m (MiddleName)
CROSS JOIN (VALUES ('C'), (NULL)) AS l (LastName)
)
SELECT t.*,
NamesConcat = ISNULL(STUFF(NamesConcat.value('.', 'NVARCHAR(MAX)'), 1, 2, ''), 'N/A')
FROM TestData AS t
CROSS APPLY
( SELECT ', ' + x.Name
FROM (VALUES
(1, t.FirstName),
(2, t.MiddleName),
(3, t.LastName)
) x (SortOrder, Name)
WHERE ISNULL(x.Name, '') <> '' -- NOT BLANK OR NULL
ORDER BY x.SortOrder
FOR XML PATH(''), TYPE
) x (NamesConcat);
Result
FirstName MiddleName LastName NamesConcat
-------------------------------------------------
A B C A, B, C
A NULL C A, C
A B NULL A, B
A NULL NULL A
NULL B C B, C
NULL NULL C C
NULL B NULL B
NULL NULL NULL N/A
select Isnull(FirstName,' ') +' '+ ','+ Isnull(MiddleName,' ')+' '+ ' ,'+ Isnull(Lastname,' ') as Name from personaldata
select FirstName +' '+','+ MiddleName +' '+',' + Lastname as Name from personaldata
Note: The Second query will work fine if all value present and if anyone is null then it will return null for Name, to avoid such kind of concern please use the first query.

Concatenate Rows into String with Many to Many Joins

I have a query that is working for almost all my data scenarios...except one. I have a master table, a detail table (with one to many line items), and many description tables that join to the detail table (Code Descriptions, etc). I need to concatenate all detail records into one string value so that I have one record per master record. So if there's 3 details for the master record, all values need to be concatenated into one record to represent the master.
My issue comes when the Master record has multiple detail records but the detail records don't have a match to the description tables 1 to 1. For instance, in my scenario the master record has 3 detail records which only one of the detail records has a description record. So 1 to 3 to 1, Master to Detail to Description. This is causing an issue. When trying to concatenate the records the code is not working because of the NULL value created from the Detail to Description join. The only way I can seem to get this to work is to do a Distinct sub-query and then do my concatenation logic on the outside of that. I feel like there has to be a better way or that I am simply missing something. I provided example code below to show my issue. There are 3 selects that get run. The first is the flat result with all records from the joins. The second is my original logic showing the flaw. The third is a working version that I am hoping someone knows how to do better. I greatly appreciate any help with this issue.
DECLARE #Notification table(
SystemID int NOT NULL,
NotificationID int
);
DECLARE #NotificationItems table(
SystemID int NOT NULL,
NotificationID VARCHAR(100),
LineItem VARCHAR(100)
);
DECLARE #NotificationCauses table(
SystemID int NOT NULL,
NotificationID VARCHAR(100),
LineItem VARCHAR(100),
TestValue VARCHAR(100)
);
INSERT INTO #Notification
SELECT 40,1 UNION
SELECT 40,2 UNION
SELECT 40,3 UNION
SELECT 40,4
INSERT INTO #NotificationItems
SELECT 40,1,1 UNION
SELECT 40,1,2 UNION
SELECT 40,1,3 UNION
SELECT 40,2,1 UNION
SELECT 40,2,2 UNION
SELECT 40,3,1
INSERT INTO #NotificationCauses
SELECT 40,1,1,'Code_A' UNION
SELECT 40,2,1,'Code_B' UNION
SELECT 40,2,2,'Code_C' UNION
SELECT 40,3,1,'Code_D'
--SELECT *
--FROM #Notification
--SELECT *
--FROM #NotificationItems
SELECT *
FROM #Notification AS n
LEFT OUTER JOIN #NotificationItems AS ni
ON n.NotificationID = ni.NotificationID
AND n.SystemID = ni.SystemID
LEFT OUTER JOIN #NotificationCauses AS nc
ON ni.NotificationID = nc.NotificationID
AND ni.SystemID = nc.SystemID
AND ni.LineItem = nc.LineItem
SELECT DISTINCT n.SystemID, n.NotificationID
,SUBSTRING(
(
SELECT DISTINCT
CASE WHEN LTRIM(RTRIM(ni1.LineItem)) <> ISNULL('','') THEN ', '+ni1.LineItem ELSE '' END AS [text()]
FROM #NotificationItems AS ni1
WHERE ni1.SystemID = ni.SystemID AND ni1.NotificationID = ni.NotificationID --AND a1.LineItem = a.LineItem
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [LineItem]
,SUBSTRING(
(
SELECT DISTINCT
CASE WHEN LTRIM(RTRIM(nc1.TestValue)) <> ISNULL('','') THEN ', '+nc1.TestValue ELSE '' END AS [text()]
FROM #NotificationCauses AS nc1
WHERE nc1.SystemID = nc.SystemID AND nc1.NotificationID = nc.NotificationID --AND nc1.LineItem = nc.LineItem
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [TestValues]
FROM #Notification AS n
LEFT OUTER JOIN #NotificationItems AS ni
ON n.SystemID = ni.SystemID
AND n.NotificationID = ni.NotificationID
LEFT OUTER JOIN #NotificationCauses AS nc
ON ni.SystemID = nc.SystemID
AND ni.NotificationID = nc.NotificationID
AND ni.LineItem = nc.LineItem
SELECT DISTINCT SystemID, NotificationID
,SUBSTRING(
(
SELECT DISTINCT
CASE WHEN LTRIM(RTRIM(a1.LineItem)) <> ISNULL('','') THEN ', '+a1.LineItem ELSE '' END AS [text()]
FROM #NotificationItems AS a1
WHERE a1.SystemID = a.SystemID AND a1.NotificationID = a.NotificationID --AND a1.LineItem = a.LineItem
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [LineItem]
,SUBSTRING(
(
SELECT DISTINCT
CASE WHEN LTRIM(RTRIM(a1.TestValue)) <> ISNULL('','') THEN ', '+a1.TestValue ELSE '' END AS [text()]
FROM #NotificationCauses AS a1
WHERE a1.SystemID = a.SystemID AND a1.NotificationID = a.NotificationID --AND a1.LineItem = a.LineItem
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [TestValues]
FROM
(
SELECT DISTINCT n.NotificationID, n.SystemID, ni.LineItem, nc.TestValue
FROM #Notification AS n
LEFT OUTER JOIN #NotificationItems AS ni
ON n.SystemID = ni.SystemID
AND n.NotificationID = ni.NotificationID
LEFT OUTER JOIN #NotificationCauses AS nc
ON ni.SystemID = nc.SystemID
AND ni.NotificationID = nc.NotificationID
AND ni.LineItem = nc.LineItem
) AS a
I have cleared up the query and that's the result
SELECT n.SystemID, n.NotificationID
, SUBSTRING((SELECT COALESCE(', ' + ni.LineItem, '') [text()]
FROM NotificationItems AS ni
WHERE ni.SystemID = n.SystemID
AND ni.NotificationID = n.NotificationID
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [LineItem]
, SUBSTRING((SELECT COALESCE(', ' + nc.TestValue, '') [text()]
FROM NotificationItems AS ni
INNER JOIN NotificationCauses nc
ON ni.SystemID = nc.SystemID
AND ni.NotificationID = nc.NotificationID
AND ni.LineItem = nc.LineItem
WHERE ni.SystemID = n.SystemID
AND ni.NotificationID = n.NotificationID
ORDER BY 1
FOR XML PATH ('')
), 2, 1000) AS [TestValues]
FROM Notification n
Those are the "smell" founded:
the ISNULL('', ''), it really does nothing, replaced with blank string '' (more to come)
the FROM of the main select, there are three table when only one is really used, the unused two are removed, that needed an update of the FROM and WHERE condition subqueries
the DISTINCT of the subqueries, again it does nothing, stripped away
the CASE in the subqueries add a comma before a value, if the trimmed value is not null, that is exactly what COALESCE(', ' + value, '') does (if the trim is needed re-add it)
Everything else is only formatting the query my way, 'cause it's easier to read if it's formatted your way (something like review by refactoring)
Here is a SQLFiddle demo of the cleared query with the data provided

TSQL Select query that generates output similar to the ms access multiple value fields

I have tables in SQL Server 2008 such as:
TopicTable
TopicID: nvarchar (Primary Key)
ProgID: nvarchar
topic1: bit
topic2: bit
topic3: bit
topic4: bit
The topic table looks something like the following:
TopicID ProgID topic1 topic2 topic3 topic4
topic001 prog001 1 1 0 0
topic002 prog002 1 0 1 1
topic003 prog003 1 0 0 0
topic004 prog004 1 1 1 1
Program table:
ProgID: nvarchar (Primary Key)
ProgramName: nvarchar
The Program table looks like this:
ProgID ProgramName
prog001 programA
prog002 programB
prog003 programC
prog004 programD
I want to create a view to get the output like:
ProgID ProgramName Topic
prog001 programA topic1,topic2
prog002 programB topic1,topic3,topic4
prog003 programB topic1
prog004 programD topic1,topic2,topic3,topic4
Please can someone help me how to get this.
Thank You.
It would look like this:
;WITH cteTopics AS (
SELECT T.ProgID
,STUFF((
SELECT T1.TopicID + ','
FROM TopicTable T1
WHERE T1.ProgID = T.ProgID
FOR XML PATH(''),TYPE).value('(./text())[1]','VARCHAR (MAX)')
,1,0,'') [Topics]
FROM TopicTable T
GROUP BY T.ProgID)
SELECT P.ProgID, P.ProgramName, T.Topics
FROM Program P
LEFT JOIN cteTopics T ON T.ProgID = P.ProgID
http://sqlfiddle.com/#!3/b9e4a/4
You will have some extra commas here but you can tweak the code a little bit more to eliminate the extra commas . this is what I have got for you so far
CREATE Table Topic (Topic NVARCHAR(20), Programe NVARCHAR(20), Topic1 bit, Topic2 bit,Topic3 bit,Topic4 bit)
GO
INSERT INTO Topic
VALUES
('topic001','prog001',1,1,0,0),
('topic002','prog002',1,0,1,1),
('topic003','prog003',1,0,0,0),
('topic004','prog004',1,1,1,1)
GO
CREATE TABLE Programe (P_ID NVARCHAR(20) , Name NVARCHAR(20))
GO
INSERT INTO Programe VALUES
('prog001','programA'),
('prog002','programB'),
('prog003','programC'),
('prog004','programD')
GO
View Definition
CREATE VIEW vw_ViewName
AS
SELECT P_ID, Name, ISNULL(STUFF(L1.Topic1L, 1, 1 , '') + ', ', '') + ISNULL(STUFF(L2.Topic2L, 1, 1, '') + ', ', '')
+ ISNULL( STUFF(L3.Topic3L, 1, 1, '')+ ', ', '') + ISNULL(STUFF(L4.Topic4L, 1, 1, '')+ ', ', '') AS Topics
FROM Programe P CROSS APPLY (
SELECT ' ' + CASE WHEN Topic1 = 1 THEN 'Topic1' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L1(Topic1L)
CROSS APPLY (
SELECT ', ' + CASE WHEN Topic2 = 1 THEN 'Topic2' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L2(Topic2L)
CROSS APPLY (
SELECT ', ' + CASE WHEN Topic3 = 1 THEN 'Topic3' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L3(Topic3L)
CROSS APPLY (
SELECT ', ' + CASE WHEN Topic4= 1 THEN 'Topic4' ELSE NULL END [text()]
FROM Topic
WHERE Programe = P.P_ID
FOR XML PATH('')
)L4(Topic4L)
RESULT SET
P_ID Name Topics
prog001 programA Topic1, Topic2,
prog002 programB Topic1, Topic3, Topic4,
prog003 programC Topic1,
prog004 programD Topic1, Topic2, Topic3, Topic4,

sql server(find the count of table base on condition)

i have a table like following
RequestNo Facility status
1 BDC1 Active
1 BDC2 Active
1 BDC3 Active
2 BDC1 Active
2 BDC2 Active
i want like this
RequestNo Facilty Count
1 BDC (1,2,3) 1
2 BDC(1,2) 1
the count should display based on Status with facilty.Fcilityv should take as BDC only
Try this, (assuming that your facility is fixed 4 character code)
SELECT RequestNo, Fname + '(' + FnoList + ')' Facilty, count(*) cnt
FROM
(
SELECT distinct RequestNo,
SUBSTRING(Facility,1,3) Fname,
stuff((
select ',' + SUBSTRING(Facility,4,4)
from Dummy
where RequestNo = A.RequestNo AND
SUBSTRING(Facility,1,3) = SUBSTRING(A.Facility,1,3)
for xml path('')
) ,
1, 1, '') as FnoList
FROM Dummy A
) x
group by RequestNo, Fname, FnoList;
SQL DEMO
This doesn't put any constraints on the length of the Facility field. It strips out the chars from the beginning and the numeric numbers from the ending:
SELECT RequestNo, FacNameNumbers, COUNT(Status) as StatusCount
FROM
(
SELECT DISTINCT
t1.RequestNo,
t1.Status,
substring(facility, 1, patindex('%[^a-zA-Z ]%',facility) - 1) +
'(' +
STUFF((
SELECT DISTINCT ', ' + t2.fac_number
FROM (
select distinct
requestno,
substring(facility, 2 + len(facility) - patindex('%[^0-9 ]%',reverse(facility)), 9999) as fac_number
from facility
) t2
WHERE t2.RequestNo = t1.RequestNo
FOR XML PATH (''))
,1,2,'') + ')' AS FacNameNumbers
FROM Facility t1
) final
GROUP BY RequestNo, FacNameNumbers
And the SQL Fiddle