Merging multiple rows of data into same column - sql

I would like to create a table of job ids and a column listing all the different job categories that get matched up, but concatenated into the same column. As an example, right now job 82041 has two categories, but now is returning two rows. I would like for it to say "Retail, Sales Associate", all in one field.
The code that I tried is below, can anybody tell me what I am doing wrong?
EXAMPLE:
jobOrderID (No column name)
82027 Motion Graphics
82029 Other
82030 Product Designer
82041 Retail
82041 Sales Associate
82069 Social Media
EXAMPLE CODE:
select JobOrder.jobOrderID ,
stuff((select distinct ', ' + cast(Category.occupation as nchar(30))
from Category
where Category.categoryID = JobOrderCategories.categoryID
for xml path ('')),1,1,'')
from JobOrder
left outer join JobOrderCategories
on JobOrder.joborderid = JobOrderCategories.jobOrderID
left outer join Category
on Category.categoryID = JobOrderCategories.categoryID
where JobOrder.dateAdded > '2017-5-2' and JobOrder.dateAdded < '2017-5-3'
and joborder.isDeleted = 0
order by joborder.dateAdded asc

Figured it out by altering the left joins
select
JobOrder.jobOrderID,
stuff((select distinct ', ' + cast(Category.occupation as varchar(30))
from Category
left outer join JobOrderCategories on (Category.categoryID = JobOrderCategories.categoryID and joborder.jobOrderID = JobOrderCategories.joborderid)
where Category.categoryID = JobOrderCategories.categoryID
for xml path ('')),1,1,'')
from JobOrder
where JobOrder.dateAdded > '2017-5-2' and JobOrder.dateAdded < '2017-5-3'
and joborder.isDeleted = 0

Related

Many Duplicates, caused by a phone number column. Need to cut down duplicates

See query below returning approx 38K rows. When 'phone' join and column are removed, it cuts down to the correct 15.5K rows.
SELECT
tc.customer_no
,fdn.display_name_short 'name'
,tc.cont_amt
,tc.ref_no
,tc.cont_dt
,tc.cont_type
,tca.fyear
,(ISNULL(street1, 'none') + ' ' + ISNULL(city, 'none') + ' ' + ISNULL(state, 'none')
+ ', ' + ISNULL(postal_code, 'none')) 'address'
,ISNULL(tp.phone, 'none')
,ISNULL(te.address, 'none')
FROM T_CONTRIBUTION tc
JOIN FT_CONSTITUENT_DISPLAY_NAME() fdn
ON tc.customer_no = fdn.customer_no
JOIN T_CAMPAIGN tca
ON tc.campaign_no = tca.campaign_no
LEFT JOIN T_ADDRESS ta
ON tc.customer_no = ta.customer_no AND ta.primary_ind = 'y'
LEFT JOIN T_EADDRESS te
ON tc.customer_no = te.customer_no AND te.primary_ind = 'y'
LEFT JOIN T_PHONE tp
ON tc.customer_no = tp.customer_no
WHERE tca.fyear BETWEEN 2018 AND 2022
AND tc.cont_amt > 0
AND te.inactive = 'N'
AND ta.inactive = 'N'
Any advice as to how i can include the phone number column, while eliminating as many duplicates as possible? I don't have to be highly precise with this query, but need to get the row count down as much as possible. The phone table has about 50 different phone types (ex. 1,2,or 22), and the PK is the phone number. The DB has since moved to using only phone type 1 or 2, but i am searching 4 yrs back which is before they switched to only using two different phone types.
Followed suggestions in comments, ended up with:
CTE to create numbered and grouped rows
WITH cte AS (
SELECT customer_no, phone
, row_number() OVER(PARTITION BY customer_no ORDER BY phone) AS rn
FROM T_PHONE
)
Then referenced said cte in the main query's select.
Finally added
WHERE cte.rn = 1
Which selected the first phone number at random, in each group of customer's phones numbers.

SSRS Subreport runs multiple times, I only want it running once

I have a report that has a drillthrough subreport that runs multiple times when it has more than one relationship to a many to many item that has nothing to do with the subreport.
Main report query
SELECT DISTINCT
cat.CategoryName AS 'Category Name', sub.SubCategoryName AS 'SubCategory Name', cur.Status, cur.PastConsiderationFlag, cur.Model, cur.Version, cur.Vendor, cur.AvailableDate AS 'Available Date', cur.EndOfProduction AS 'End of Production',
cur.EndOfSupport AS 'End of Support', dep.DepartmentName AS 'Department Name', emp.FirstName + ' ' + emp.LastName AS 'Tech Owner', emp2.FirstName + ' ' + emp2.LastName AS 'Tech Contact',
cur.NumOfDevices AS '# of Devices', cur.UpgradeDuration AS 'Upgrade Duration', cur.FiscalConsideration AS 'Fiscal Consideration', cur.Description, cur.SupportingComments, cur.CurrencyId, STUFF
((SELECT ', ' + pl.PlatformName AS Expr1
FROM Platform AS pl LEFT OUTER JOIN
Currency_Platform AS cp ON cur.CurrencyId = cp.CurrencyId
WHERE (pl.PlatformId = cp.PlatformId) FOR XML PATH('')), 1, 1, '') AS 'Platforms', ISNULL(STUFF
((SELECT ', ' + cu2.Model AS Expr1
FROM Currency AS cu2 RIGHT OUTER JOIN
Currency_Dependency AS cd ON cur.CurrencyId = cd.CurrencyId
WHERE (cu2.CurrencyId = cd.DependencyId) FOR XML PATH('')), 1, 1, ''), 'N/A') AS 'Dependencies', ISNULL(STUFF
((SELECT ', ' + cu2.Model AS Expr1
FROM Currency AS cu2 RIGHT OUTER JOIN
Currency_Affected AS ca ON cur.CurrencyId = ca.CurrencyId
WHERE (cu2.CurrencyId = ca.AffectedId) FOR XML PATH('')), 1, 1, ''), 'N/A') AS 'Affected Apps', Currency_Platform.PlatformId
FROM Currency AS cur INNER JOIN
SubCategory AS sub ON cur.SubCategoryId = sub.SubCategoryId INNER JOIN
Category AS cat ON sub.CategoryId = cat.CategoryId LEFT OUTER JOIN
Employee AS emp ON cur.OwnerId = emp.EmployeeId LEFT OUTER JOIN
Employee AS emp2 ON cur.ContactId = emp2.EmployeeId LEFT OUTER JOIN
Department AS dep ON cur.PortfolioOwnerId = dep.DepartmentId LEFT OUTER JOIN
Currency_Platform ON cur.CurrencyId = Currency_Platform.CurrencyId
Even though it's a distinct select, the subreport will run equal to the amount of Platforms it belongs to. I'll include the Query for the subreport here.
;with cte as (
-- anchor elements: where curr.Status = 1 and not a dependent
select
CurrencyId
, Model
, Version
, ParentId = null
, ParentModel = convert(varchar(128),'')
, Root = curr.Model
, [Level] = convert(int,0)
, [ParentPath] = convert(varchar(512),Model + Version)
from dbo.Currency as curr
where curr.Status = 1
/* anchor's do not depend on any other currency */
and not exists (
select 1
from dbo.Currency_Dependency i
where curr.CurrencyId = i.DependencyId
)
-- recursion begins here
union all
select
CurrencyId = c.CurrencyId
, Model = c.Model
, Version = c.Version
, ParentId = p.CurrencyId
, ParentModel = convert(varchar(128),p.Model + p.Version)
, Root = p.Root
, [Level] = p.[Level] + 1
, [ParentPath] = convert(varchar(512),p.[ParentPath] + ' > ' + c.Model + ' ' + c.Version)
from dbo.Currency as c
inner join dbo.Currency_Dependency as dep
on c.CurrencyId = dep.DependencyId
inner join cte as p
on dep.CurrencyId = p.CurrencyId
)
select CurrencyId, ParentPath, Model + ' ' + Version AS 'Model' from cte
WHERE CurrencyId = #CurrencyId
When I run the subreport individually, everything is fine. When I open the subreport through the main report passing the CurrencyId as a parameter, it does so as many times as the amount of platforms it belongs to.
Is there a way I can correct this either by improving the queries, or as I would prefer, force the subreport to only run once no matter what?
Thanks so much for having a look.
You can use SQL Server Profiler to check the following things.
How many times and with what parameters is the subreport query has ran
How many values your first query returned
I don't think your problem is more about SSRS than it is about your T-SQL Code. I'm going to guess and say that the subreport object is in the report detail section of the report. That means that the subreport is going to render once for every row in the main queries dataset. I don't have any idea what your container report actually looks like but one option you have might be to include the subreport in the header or footer section and have it run off of a MAX(), MIN(), of a value that you know will be the same for every row.

SQL Joining tables with 'constants'

I have a table of orders,
Invoice Location Customer Code SalesPersonEmail
------------------------------------------------------
300001 001 CUS001 ?
300002 006 CUS002 ?
And a table of email groups,
Role Email
-----------------------------------------------------
Filtered_Group Management#gmail.com;john#gmail.com
When Location = 001, SalesPersonEmail must be the Email field from Filtered_Group
SalesPersonEmail for all other locations must be "Orders#gmail.com;" + the Email for Role No_Filter_Group.
I'm currently using the following to achieve this,
SELECT i.Invoice, i.Location, i.[Customer Code],
CASE WHEN i.Location = 001
THEN f.Email
ELSE N'Orders#gmail.com;' + nf.Email as SalesPersonEmail
END
FROM Invoice i, RoleCodes f, RoleCodes nf
WHERE f.Role = N'Filtered_Group' AND nf.Role = N'No_Filter_Group'
My problem is the Role No_Filter_Group may not exist in the Role table at times, which causes the above query to return nothing.
How do I join these tables properly so if No_Filter_Group does not exist in the table, rows that have a SalesPersonEmail of Filtered_Group are still returned from the query?
Thanks
A relatively simple way is to use LEFT JOIN and put the special number 001 for your location and special role names Filtered_Group and No_Filter_Group in the join condition.
In this SQL Fiddle you can comment/uncomment one line in the schema definition to see how it works when RoleCodes has a row with No_Filter_Group and when it doesn't.
In any case, the query would return all rows from Invoice table.
SELECT
Invoice.Invoice
,Invoice.Location
,Invoice.[Customer Code]
,CASE WHEN Invoice.Location = '001'
THEN RoleCodes.Email
ELSE 'Orders#gmail.com;' + ISNULL(RoleCodes.Email, '')
END AS SalesPersonEmail
FROM
Invoice
LEFT JOIN RoleCodes ON
(Invoice.Location = '001'
AND RoleCodes.Role = 'Filtered_Group')
OR
(Invoice.Location <> '001'
AND RoleCodes.Role = 'No_Filter_Group')
Try something like this.
Note: This is just a example am not sure about the tables and column of your schema. Replace with the respective tables and columns
SELECT CASE
WHEN location = '001' THEN (SELECT TOP 1 email
FROM email_table
WHERE [role] = 'Filtered_Group')
ELSE 'Orders#gmail.com;'
END
FROM orders
If email_table table will have only one row for [role] = 'Filtered_Group' then you can remove the TOP 1 from the sub-query
Left join or an easier, albeit less efficient method would be to do a subquery in the select statement itself.
SELECT i.Invoice, i.Location, i.[Customer Code],
CASE WHEN i.Location = 001
THEN (SELECT TOP 1 f.Email FROM RoleCodes f WHERE f.Role = N'Filtered_Group')
ELSE N'Orders#gmail.com;' + ISNULL( (SELECT nf.Email as SalesPersonEmail FROM RoleCodes nf WHERE nf.Role = N'No_Filter_Group'), '')
END
FROM Invoice i
Normally you would want to join these in on each other but I'm not certain how you would do that with the schema provided.
Nested select will be run for each row, instead, you could try this :-
Select i.Invoice
,i.Location
,i.CustomerCode
,Isnull(r.Email,'Orders#gmail.com') As SalesPersonEmail
From Invoice As i With (Nolock)
Left Join
(
Select rc.Email
,'001' As Location
From RoleCodes As rc With (Nolock)
Where rc.Role = 'Filtered_Group'
) As r On i.Location = r.Location
use the following Query:
select t.Invoice,t.Location,t.[Customer Code],
case t.Location
when '001' then
t2.Email
else
'Orders#gmail.com'
end
as
Salespersonemail
from orders t
join email_groups t2 on t2.Role='Filtered_Group'

Invalid Column name while running a query

I am new to SQL and I don't know what's wrong in this query,
SELECT
wo.WORKORDERID "Request ID", (wo.CREATEDTIME) "Created on",
aau.FIRST_NAME "Requester", aac.EMAILID 'From',
[To] = STUFF((SELECT ', ' + Recipient_email
FROM workorder_recipients wor2
WHERE wor2.Workorderid = wor.Workorderid and wor2.To_cc_bcc='To'
FOR XML PATH('')), 1, 2, ''),
[CC] = STUFF((SELECT ', ' + Recipient_email
FROM workorder_recipients wor2
WHERE wor2.Workorderid = wor.Workorderid and wor2.To_cc_bcc='CC'
FOR XML PATH('')), 1, 2, ''),
cd.CATEGORYNAME "Category"
FROM
workorder_recipients wor
LEFT JOIN
workorder wo ON wor.workorderid = wo.workorderid
LEFT JOIN
ModeDefinition mdd ON wo.MODEID = mdd.MODEID
LEFT JOIN
SDUser sdu ON wo.REQUESTERID = sdu.USERID
LEFT JOIN
AaaUser aau ON sdu.USERID = aau.USER_ID
LEFT JOIN
SDUser crd ON wo.CREATEDBYID = crd.USERID
LEFT JOIN
AaaUser cri ON crd.USERID = cri.USER_ID
LEFT JOIN
AaaUserContactInfo aauc ON aau.USER_ID = aauc.USER_ID
LEFT JOIN
AaaContactInfo aac ON aauc.CONTACTINFO_ID = aac.CONTACTINFO_ID
LEFT JOIN
WorkOrderStates wos ON wo.WORKORDERID = wos.WORKORDERID
LEFT JOIN
CategoryDefinition cd ON wos.CATEGORYID = cd.CATEGORYID
WHERE
mdd.MODENAME = 'E-Mail'
AND cd.CATEGORYNAME in ('Agent Operational Technology (EMEA/UK/IE)','Client Technology')
AND wo.IS_CATALOG_TEMPLATE='0'
AND wo.CREATEDTIME >= 1416783600000
AND wo.CREATEDTIME <= 1417388399000
AND wo.ISPARENT='1'
GROUP BY
wo.workorderid
But I keep getting this error:
Column 'workorder_recipients.WORKORDERID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Thanks,
Atul
Imagine the following simple table (T) where ID is the primary key:
ID | Column1 | Column2 |
----|---------+----------|
1 | A | X |
2 | A | Y |
Then you write the following query
SELECT ID, Column1, Column2
FROM T
GROUP BY Column1;
This breaks the SQL Standard, and if it were to run without errors (which it would in MySQL), the result:
ID | Column1 | Column2 |
----|---------+----------|
1 | A | X |
Is no more or less correct than
ID | Column1 | Column2 |
----|---------+----------|
2 | A | Y |
So what you are saying is give me one row for each distinct value of Column1, which both results sets satisfy, so how do you know which one you will get? Well you don't.
For simplicity sake (and the way it is implemented in SQL Server) we state the rule that if an column is not contained in an aggregate function, it must be in the GROUP BY clause for it to appear in the select list. This is not strictly true, the SQL-Standard does allow columns in the select list not contained in the GROUP BY or an aggregate function, however these columns must be functionally dependent on a column in the GROUP BY. From the SQL-2003-Standard (5WD-02-Foundation-2003-09 - page 346) - http://www.wiscorp.com/sql_2003_standard.zip
15) If T is a grouped table, then let G be the set of grouping columns of T. In each contained
in , each column reference that references a column of T shall reference some column C that
is functionally dependent on G or shall be contained in an aggregated argument of a
whose aggregation query is QS.
For example, ID in the sample table is the PRIMARY KEY, so we know it is unique in the table, so the following query conforms to the SQL standard and would run in MySQL and fail in many DBMS currently (At the time of writing Postgresql is the closest DBMS I know of to correctly implementing the standard - Example here):
SELECT ID, Column1, Column2
FROM T
GROUP BY ID;
Since ID is unique for each row, there can only be one value of Column1 for each ID, one value of Column2 there is no ambiguity about
what to return for each row. As far as I know, Postgresql is the only DBMS that has gone anyway to implementing this.
In order for your query to work you would need to add some columns to the GROUP BY:
GROUP BY wo.workorderid, wo.CREATEDTIME, aau.FIRST_NAME, aac.EMAILID, cd.CATEGORYNAME
However, I think you can remove the issue of duplicates by removing workorder_recipients from your FROM, you don't appear to use this anywhere. Removing this reference should remove the need for GROUP BY
SELECT
[Request ID] = wo.WORKORDERID,
[Created on] = wo.CREATEDTIME,
[Requester] = aau.FIRST_NAME,
[From] = aac.EMAILID,
[To] = STUFF((SELECT ', ' + Recipient_email
FROM workorder_recipients wor2
WHERE wor2.Workorderid = wo.Workorderid
AND wor2.To_cc_bcc='To'
FOR XML PATH('')), 1, 2, ''),
[CC] = STUFF((SELECT ', ' + Recipient_email
FROM workorder_recipients wor2
WHERE wor2.Workorderid = wo.Workorderid
AND wor2.To_cc_bcc='CC'
FOR XML PATH('')), 1, 2, ''),
[Category] = cd.CATEGORYNAME
FROM workorder wo
LEFT JOIN ModeDefinition AS mdd
ON wo.MODEID = mdd.MODEID
LEFT JOIN SDUser AS sdu
ON wo.REQUESTERID = sdu.USERID
LEFT JOIN AaaUser AS aau
ON sdu.USERID = aau.USER_ID
LEFT JOIN SDUser AS crd
ON wo.CREATEDBYID = crd.USERID
LEFT JOIN AaaUser AS cri
ON crd.USERID = cri.USER_ID
LEFT JOIN AaaUserContactInfo AS aauc
ON aau.USER_ID = aauc.USER_ID
LEFT JOIN AaaContactInfo AS aac
ON aauc.CONTACTINFO_ID = aac.CONTACTINFO_ID
LEFT JOIN WorkOrderStates AS wos
ON wo.WORKORDERID = wos.WORKORDERID
LEFT JOIN CategoryDefinition AS cd
ON wos.CATEGORYID = cd.CATEGORYID
WHERE
mdd.MODENAME = 'E-Mail'
AND cd.CATEGORYNAME in ('Agent Operational Technology (EMEA/UK/IE)','Client Technology')
AND wo.IS_CATALOG_TEMPLATE='0'
AND wo.CREATEDTIME >= 1416783600000
AND wo.CREATEDTIME <= 1417388399000
AND wo.ISPARENT='1';
when you use GROUP BY in a query, you need to include every field in the group by which is in the select, except ones where you're aggregating - such as a SUM a MIN or a MAX (Amongst others).
So, to contrive an example, this would be invalid:
SELECT FirstName, LastName, SUM(Score)
FROM HighScores
GROUP BY FirstName
You would also need to include LastName in the GROUP BY to get the sum of a person's scores

MS SQL Conditional Join

I have a SQL Query :
SELECT * FROM Customer c
LEFT JOIN Invoice I ON I.InvcNum = C.Cust_InvcNum
some thing changed and the join does not work because there is no consistency in the data in the 'Cust_InvcNum'. So now when it does not find the record for the join or if it is null it needs to check for another condition.
LEFT JOIN Invoice I ON I.InvcNum = (SELECT p.InvcPrefix FROM Prefix WHERE p.DealerID = I.DealrID ) + '-' + I.InvcNum
second join I do works but it is taking too long for it get me data. Is there any other way to do this.
Earlier it used to be
Join on I.InvcNum = C.Cust_InvcNum
both the columns has the same data like DlrCd-InvcNum i.e both the columns 1234-A789
but not it could match on the above data or now the column 'InvcNum' in invoice table
can be populated like Dlrd-InvcNum or InvcPrefix-InvcNum
So InvcNum = 1234-A789 but CustNum = I94-A789
so we need to check if the for InvoicePrefix-InvcNum
SELECT *
FROM Customer c
LEFT JOIN (
SELECT i.InvcNum, p.InvcPrefix + '-' + I.InvcNum AS pInvcNum
FROM Invoice i LEFT JOIN Prefix p ON i.DealrID = p.DealrID
) ip ON c.Cust_InvcNum = CASE WHEN c.Cust_InvcNum = ip.InvcNum
THEN ip.InvcNum
ELSE ip.pInvcNum END