I have a SQL database and I am writing a query:
SELECT *
FROM Consignments
INNER JOIN OrderDetail
ON Consignments.consignment_id = OrderDetail.consignment_id
INNER JOIN UserReferences
ON OrderDetail.record_id = UserReferences.record_id
WHERE Consignments.despatch_date = '2020-04-23'
Within the first column is:consignment_id [this is from the Consignments table]In the final column is:senders_reference [this is from the UserReferences table]
Now - the issue I have is - that when I am running the query to pick up all consignments for a particular date - it is displaying multiple rows (with duplicated consignment_id) when there are multiple senders references within the database.
If there is one senders reference number - then there is only 1 row.
This makes sense - because within the front-end for the database the user can enter 1 or more senders references.
Now - what I would like to do is to amend my query for the resulting data to only display 1 row for all consignments and if there are multiple senders reference numbers - to have them within the one field, separated by commas.
Is this doable from the query stage?
Or if not - after export, is it possible to develop a bat file to do the same thing?
For reference - this is what I mean - this is the result I am getting at the moment:
This is what I need:
You can use older style with the help of for xml :
select t.consignment_id,
stuff((select ', ' +convert(varchar(255), t1.sender_reference)
from table t1
where t1.consignment_id = t.consignment_id
for xml path('')
), 1, 1, ''
) as senders_reference
from (select distinct consignment_id from table t) t;
Edit : You can use CTE :
with cte as (
<your query>
)
select t.consignment_id,
stuff((select ', ' +convert(varchar(255), t1.sender_reference)
from cte t1
where t1.consignment_id = t.consignment_id
for xml path('')
), 1, 1, ''
) as senders_reference
from (select distinct consignment_id from cte t) t;
You seem to want to use the STRING_AGG function.
This answer covers it nicely
ListAGG in SQLSERVER
Related
I found the perfect example while browsing through sites of what I'm looking for. In this code example, all country names that appear in long formatted rows are concatenated together into one result, with a comma and space between each country.
Select CountryName from Application.Countries;
Select SUBSTRING(
(
SELECT ',' + CountryName AS 'data()'
FROM Application.Countries FOR XML PATH('')
), 2 , 9999) As Countries
Source: https://www.mytecbits.com/microsoft/sql-server/concatenate-multiple-rows-into-single-string
My question is: how can you partition these results with a second column that would read as "Continent" in such a way that each country would appear within its respective continent? The theoretical "OVER (PARTITION BY Continent)" in this example would not work without an aggregate function before it. Perhaps there is a better way to accomplish this? Thanks.
Use a continents table (you seem not to have one, so derive one with distinct), and then use the same code in a cross apply using the where as a "join" condition:
select *
from
(
select distinct continent from Application.Countries
) t1
cross apply
(
Select SUBSTRING(
(
SELECT ',' + CountryName AS 'data()'
FROM Application.Countries as c FOR XML PATH('')
where c.continent=t1.continent
), 2 , 9999) As Countries
) t2
Note that it is more usual, and arguably has more finesse, to use stuff(x,1,1,'')instead of substring(x,2,9999) to remove the first comma.
I want to combine the Currency field by comparing Config and Product Column. If both field is repeated with duplicate values but different currency, the combine the currency into single row as you see in the screenshot.
I tried the code like
Select DISTINCT LC.Config, LC.Product, CONCAT(LC.Currency,',',RC.Currency) as Currencies FROM [t_LimitCurrency] LC INNER JOIN [t_LimitCurrency] RC ON LC.[Config] = RC.[Config] AND LC.Product = RC.Product
Please let me know, how to write select statement for this scenario.
Below Code should do the trick. I am using XML Path but you can use String_AGG in latest version of sql server
select distinct Config,Product,
STUFF((SELECT ' ,' + CAST(Currency AS VARCHAR(max)) [text()]
FROM (
SELECT Currency
FROM Yourtable b
WHERE a.Config=b.Config and a.product=b.product
) ap
FOR XML PATH(''), TYPE)
.value('.','NVARCHAR(MAX)'),1,2,' ') Currency
from Yourtable a
EDIT 1 : for latest version of sql server code should be like below
select distinct Config,Product,
(SELECT
STRING_AGG(CONVERT(NVARCHAR(max),Currency), ',')
FROM YourTable b WHERE a.Config=b.Config and a.product=b.product)
Currency
from Yourtable a
I have the following two tables in sql.I want to get the calendarId from calenderschedule and join with calendar table to get the calendarcode for each productId. Output format is described below.
MS SQL Server 2012 version string_split is not working. Please help to get the desired output.
Table1: calenderschedule
productid, calendarid
100 1,2,3
200 1,2
Table2: calendar
calendarid, calendarCode
1 SIB
2 SIN
3 SIS
Output:
productId, calendarCode
100 SIB,SIN,SIS
200 SIB,SIN
You can normalize the data by converting to XML and then using CROSS APPLY to split it. Once it's normalized, use the STUFF function to combine the calendar codes into a comma-separated list. Try this:
;WITH normalized_data as (
SELECT to_xml.productid
,split.split_calendarid
FROM
(
SELECT *,
cast('<X>'+replace(cs.calendarid,',','</X><X>')+'</X>' as XML) as xmlfilter
FROM calendarschedule cs
) to_xml
CROSS APPLY
(
SELECT new.D.value('.','varchar(50)') as split_calendarid
FROM to_xml.xmlfilter.nodes('X') as new(D)
) split
) select distinct
n.productid
,STUFF(
(SELECT distinct ', ' + c.calendarCode
FROM calendar c
JOIN normalized_data n2 on n2.split_calendarid = c.calendarid
WHERE n2.productid = n.productid
FOR XML PATH ('')), 1, 1, '') calendarCode
from normalized_data n
I feel like this solution is a bit overly complex, but it's the only way I got it to work. If anybody knows how to simplify it, I'd love to hear some feedback.
I want to have a SELECT that as part of list of return fields would also include a csv of multiple values from another table.
I have code working to determine the CSV from here:
SQL Server 2008 Rows to 1 CSV field
But i am not able to get a working JOIN with the csv value, or get at the id field of the derived csv values.
My two tables are:
job (id,title,location)
skills(id, jobID, skillName, listOrder)
I want to do a select * from job with each job record having its own derived skills
basically result should be:
1,dba,texas, [sql,xml,rdp] <-- skills for jobid=1
This seems to do, what you are looking for:
SELECT
J.id
, J.title
, J.location
, '[' + STUFF ((SELECT ',' + S.skillName
FROM Skills S
WHERE
J.id = S.jobID
ORDER BY S.listOrder
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)')
, 1, 1, '') + ']' skillSet
FROM Job J
GROUP BY J.id, J.title, J.location
;
See it in action: SQL Fiddle
Please comment, if and as this requires adjustment / further detail.
I need to turning the value of a row into column - for example:
SELECT s.section_name,
s.section_value
FROM tbl_sections s
this outputs :
section_name section_value
-----------------------------
sectionI One
sectionII Two
sectionIII Three
desired output :
sectionI sectionII sectionIII
-----------------------------------------
One Two Three
This is probably better done client-side in the programming language of your choice.
You absolutely need to know the section names in advance to turn them into column names.
Updated answer for Oracle 11g (using the new PIVOT operator):
SELECT * FROM
(SELECT section_name, section_value FROM tbl_sections)
PIVOT
MAX(section_value)
FOR (section_name) IN ('sectionI', 'sectionII', 'sectionIII')
For older versions, you could do some self-joins:
WITH
SELECT section_name, section_value FROM tbl_sections
AS
data
SELECT
one.section_value 'sectionI',
two.section_value 'sectionII',
three.section_value 'sectionIII'
FROM
select selection_value from data where section_name = 'sectionI' one
CROSS JOIN
select selection_value from data where section_name = 'sectionII' two
CROSS JOIN
select selection_value from data where section_name = 'sectionIII' three
or also use the MAX trick and "aggregate":
SELECT
MAX(DECODE(section_name, 'sectionI', section_value, '')) 'sectionI',
MAX(DECODE(section_name, 'sectionII', section_value, '')) 'sectionII',
MAX(DECODE(section_name, 'sectionIII', section_value, '')) 'sectionIII'
FROM tbl_sections