Set Duplicate Row as One Row AND one Different Column Value Merge - sql

I have ONE table like this
in this table orderID column is repeat but its CollectDate is different
So i want to SET MY table AS means IF OrderID Same then concatenate Collect Date
MY query is following and its work
SELECT distinct df.OrderId as OrderId,df.FileName as FileName, df.RandomKey as RandomKey,
df.ClientId as ClientId, df.ProjectId as ProjectId, df.Status as Status,df.UserId as UserId,
df.emailTo as emailTo,df.PackageType as PackageType,df.RequestedDatetime as RequestedDatetime,
STUFF(
(SELECT ' | ' + convert(varchar(10),ord.CollectDate, 101)
FROM SMXPSU.OrderDetails ord
WHERE df.OrderId =ord.OrderId --and ord.OrderId in(getdate()-30)
FOR XML PATH('')),1,1,'') AS CollectDate
FROM SMXPSU.downloadfiles AS df
INNER Join
SMXPSU.OrderDetails ord (NOLOCK)
ON df.OrderId=ord.OrderId
WHERE df.ClientId='shaw22' and df.PackageType='Hard Copy' and df.RequestedDatetime>=getdate()-30
GROUP BY df.OrderId,FileName,PackageType,RequestedDatetime,RandomKey,ClientId,ProjectId,Status,UserId,emailTo,PackageType,RequestedDatetime,CollectDate
order by df.OrderId desc ![enter image description here][3]
But Output give me like this
Means if CollectDate same then cumming multiple time but i want only one time if same

You can try the following query
;WITH order_cte
AS
(
SELECT OrderId,RandomKey,PackageType,RequestedDate,
(
SELECT CAST(CAST(orders.CollectedData AS DATE) AS VARCHAR) + '-' AS 'text()'
FROM Orders WHERE Orders.OrderId=o.OrderId
FOR XML Path('')
) [CollectDate]
FROM Orders o
GROUP BY OrderId,RandomKey,PackageType,RequestedDate
)
SELECT OrderId,RandomKey,PackageType,RequestedDate,LEFT([CollectDate],LEN([CollectDate])-1) AS [CollectDate]
FROM order_cte;

SELECT OrderId, RandomKey, PackageType, RequestedDate,
CASE
WHEN COUNT(*)=1 THEN CAST(MIN(CollectDate) AS VARCHAR(20))
ELSE CAST(MIN(CollectDate) AS VARCHAR(20)) + '-' + CAST(MAX(CollectDate) AS VARCHAR (20)) AS CollectDate
FROM
Table
GROUP BY OrderId, RandomKey, PackageType, RequestedDate

Related

SQL Server use column value as column names and convert to json array

Let's say I have the following table ProductValues:
ProductID
Name
Value
1
Market
A
1
Customer
B
2
Market
C
2
Customer
D
I'm able to group them by their ProductID and get these values as an array with the following code:
SELECT
(
SELECT Name, Value FROM ProductValues
WHERE P.ID = ProductID
FOR JSON PATH
)
FROM #ProductIDs P '#ProductIDs is a table containing the productIDs that Id like to retrieve'
This returns the following:
(No column name)
[{"Name":"Market","Value":"A"},{"Name":"Customer","Value":"B"}]
[{"Name":"Market","Value":"C"},{"Name":"Customer","Value":"D"}]
I would like to dynamically create key value pairs using Pivot. I want to achieve the following:
(No column name)
[{"Market":"A"},{"Customer":"B"}]
[{"Market":"C"},{"Customer":"D"}]
Looking at another answer, I tried the following, but this doesn't set the keys dynamically and won't execute (states that "Value" and "TechName" in the Pivot are undefined):
SELECT(
SELECT Market, Customer
FOR JSON PATH
)
FROM(
SELECT(
SELECT Name, Value FROM ProductValues
WHERE ProductID = P.ID
)
FROM #ProductIDs P
) t
PIVOT(
MAX(Value) '<--- "Value" Undefined'
FOR Name IN ( '<--- "Name" Undefined'
Market, Customer
)
) AS pvt
GROUP BY
Market, Customer
You can pivot with conditional aggregation, the convert to JSON:
select (
select
max(case when name = 'Market' then value end) as market,
max(case when name = 'Customer' then value end) as customer
from productvalues pv
where pv.productid = p.productid
for json path
) as js
from #ProductIDs p
Here is a demo on DB Fiddle.
SQL Server is declarative by design. If you are looking for dynamic columns, you will need DYNAMIC SQL.
Example
Declare #sql nvarchar(max) = stuff( (Select Distinct ','+QUOTENAME(Name) From ProductValues FOR XML PATH('')),1,1,'')
SET #sql = 'Select B.*
From (
SELECT '+#sql+'
FROM ProductValues
PIVOT (max([Value]) FOR [Name] IN ('+#sql+')) AS pvt
) A
Cross Apply ( (Select A.* for json path ) ) B (JSONData)'
exec(#sql)
Returns
JSONData
[{"Customer":"B","Market":"A"}]
[{"Customer":"D","Market":"C"}]

How to get data from 2 rows which has same data in all columns except one in MSSQL

As in my title I want to take data from 2 rows but In my case each 2nd row has one different value compare to the first row.
I want to take all the common data along with the different data as a single row .
Here you can see each row has same values in another row except the 2nd rows last column.
Thanks.
Edits Result :
I suspect you have a some kind of ordering columns that could specify your actual data ordering if so, then you can use row_number() function
select * from (
select *,
row_number() over (partition by <common data cols> order by ? desc) Seq
from table t
) t
where seq = 1;
EDIT : I don't believe your inventort_item_id columns but yes you could use creation_date for ordering purpose
SELECT
EPI.ITEM_CODE, LMP.PROD_DESC, LLPC.COLOC_PROD_PRICE,
BASE_PATH + '' + EPI.IMAGE_FOLDER_NAME + '/' + EPI.IMAGE_DESCRIPTION AS POPULAR_PRODUCTS_IMAGE_PATHS
FROM (SELECT *,
ROW_NUMBER() OVER (PARTITION BY ITEM_CODE ORDER BY creation_date DESC) as Seq
FROM ECOM_PRODUCT_IMAGES EPI
) EPI
INNER JOIN ECOM_POPULAR_PRODUCTS_MAPPING EPPIM ON EPPIM.ITEM_CODE = EPI.ITEM_CODE
INNER JOIN LOM_MST_PRODUCT LMP ON LMP.PROD_CODE = EPI.ITEM_CODE
INNER JOIN LOM_LNK_PROD_COMP LLPC ON LLPC.COLOC_PROD_CODE = LMP.PROD_CODE
WHERE EPI.Seq = 1 AND
EPPIM.ITEM_STATUS = 'ACTIVE';
EDIT 2: In that case you need to use GROUP BY clause with conditional aggregation
SELECT
EPI.ITEM_CODE, LMP.PROD_DESC, LLPC.COLOC_PROD_PRICE,
MAX(CASE WHEN EPI.Seq = 2
THEN (BASE_PATH + '' + EPI.IMAGE_FOLDER_NAME + '/' + EPI.IMAGE_DESCRIPTION)
END) AS POPULAR_PRODUCTS_IMAGE_PATHS,
MAX(CASE WHEN EPI.Seq = 1
THEN (BASE_PATH + '' + EPI.IMAGE_FOLDER_NAME + '/' + EPI.IMAGE_DESCRIPTION)
END) AS PATH_NEW
FROM (SELECT *,
ROW_NUMBER() OVER (PARTITION BY ITEM_CODE ORDER BY creation_date DESC) as Seq
FROM ECOM_PRODUCT_IMAGES EPI
) EPI
INNER JOIN ECOM_POPULAR_PRODUCTS_MAPPING EPPIM ON EPPIM.ITEM_CODE = EPI.ITEM_CODE
INNER JOIN LOM_MST_PRODUCT LMP ON LMP.PROD_CODE = EPI.ITEM_CODE
INNER JOIN LOM_LNK_PROD_COMP LLPC ON LLPC.COLOC_PROD_CODE = LMP.PROD_CODE
WHERE EPPIM.ITEM_STATUS = 'ACTIVE'
GROUP BY EPI.ITEM_CODE, LMP.PROD_DESC, LLPC.COLOC_PROD_PRICE;
here is my approach, also using a window function.
sample data
if object_id('tempdb..#x') is not null drop table #x
CREATE TABLE #x (ITEM_CODE VARCHAR(10), PROD_DESC VARCHAR(20),
COLOR_PROD_PRICE DECIMAL, POPULAR_PRODUCTS_IMAGE_PATHS VARCHAR(200))
INSERT INTO #X(ITEM_CODE,PROD_DESC,COLOR_PROD_PRICE,POPULAR_PRODUCTS_IMAGE_PATHS) VALUES
('P0001', 'Axe Brand', 88.000, 'some_path_to_img1.jpg'),
('P0001', 'Axe Brand', 88.000, 'some_path_to_img2.jpg'),
('P0002', 'Almond Nuts', 499.000, 'some_path_to_img1.jpg'),
('P0002', 'Almond Nuts', 499.000, 'some_path_to_img2.jpg')
query - just change #x to your table and it should work
;WITH my_cte as
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY ITEM_CODE ORDER BY POPULAR_PRODUCTS_IMAGE_PATHS) AS 'track_row'
FROM #x
)
SELECT a.ITEM_CODE, a.PROD_DESC, a.COLOR_PROD_PRICE,
a.POPULAR_PRODUCTS_IMAGE_PATHS + ' ' + b.POPULAR_PRODUCTS_IMAGE_PATHS AS 'POPULAR_PRODUCTS_IMAGE_PATHS'
FROM my_cte AS a
INNER JOIN
my_cte AS b ON a.ITEM_CODE=b.ITEM_CODE
WHERE a.track_row=1 AND b.track_row=2
output
ITEM_CODE PROD_DESC COLOR_PROD_PRICE POPULAR_PRODUCTS_IMAGE_PATHS
P0001 Axe Brand 88 some_path_to_img1.jpg some_path_to_img2.jpg
P0002 Almond Nuts 499 some_path_to_img1.jpg some_path_to_img2.jpg

How can i use stuff function for multiple columns in SQL server?

I have a requirement for concatenating two values of two rows having same Id's and averaging for other column. Here is the sample table I have:
Now my requirement is I need to concatenate the Response column, concatenate Response Rating column and average the Rating Avg column if it has same ParticipantId, UseriD, QuestionId and ConductedById.
Here is the target data what I wanted:
Here Response column and Response rating column is concatenated with respective rows and Rating Avg column is taken the average. I have done one column concatenation previously using stuff function. Can this be achieved using stuff function?
You can do the following. Just group by those columns and make 2 subselects for concatenated columns:
select UserID,
ConductedByID,
QuestionID,
(SELECT STUFF((SELECT ';' + Response
FROM TableName tn2 WHERE tn1.UserID = tn2.UserID and
tn1.ConductedByID = tn2.ConductedByID and
tn1.QuestionID = tn2.QuestionID and
tn1.ParticipantID = tn2.ParticipantID
FOR XML PATH('')) ,1,1,'')) as Response,
(SELECT STUFF((SELECT ';' + cast(Rating as varchar)
FROM TableName tn2 WHERE tn1.UserID = tn2.UserID and
tn1.ConductedByID = tn2.ConductedByID and
tn1.QuestionID = tn2.QuestionID and
tn1.ParticipantID = tn2.ParticipantID
FOR XML PATH('')) ,1,1,'')) as [Response Rating],
AVG(case when Rating = 'n/a' then 0 else cast(Rating as int) end) as [Rating Avg],
ParticipantID
from TableName tn1
group by UserID, ConductedByID, QuestionID, ParticipantID
This works perfectly
STUFF(
(
SELECT DISTINCT ',' + val_name
FROM t_t43_value_set
INNER JOIN t_t43_factory
ON val_id = fac_country
INNER JOIN t_t43_delivery delivery
ON pvs_part_version_id = del_part_version_id
AND pvs_supplier_id = del_supplier_id
AND del_factory_id = fac_factory_id FOR xml path('')),1,1,'') AS 'Country'

Dynamic SubSelects in SQL Select Statement

I am querying a table for some basic information, file number, case type, status, etc. In addition I need a column for every single one of 138 case status types that will display the date the case had that status. Here is a sample:
SELECT FileNum,
CaseType,
CurrentCaseStatus,
(SELECT TOP 1 EventDt FROM caseStatusHistory WHERE CaseID = c.caseID AND CaseStatus = 'CS001' ORDER BY EventDt DESC) AS [Charge - Phone],
(SELECT TOP 1 EventDt FROM caseStatusHistory WHERE CaseID = c.caseID AND CaseStatus = 'CS002' ORDER BY EventDt DESC) AS [Charge - Written],
-- 136 more just like the live above
FROM Case c
I can query another table for all the case status types:
SELECT Code, Description
FROM caseStatus
WHERE Code BETWEEN 'CS001' AND 'CS138'
ORDER BY Code
How can I dynamically create each of those columns instead of having to manually write 138 select statements?
That's going to be terribly slow -- 138 correlated subqueries. I think you can achieve the same result with an OUTER JOIN and a GROUP BY with MAX and CASE:
Select c.filenum,
c.casetype,
c.currentcasestatus,
max(case when csh.CaseStatus = 'CS001' then EventDt end) as [Charge - Phone],
max(case when csh.CaseStatus = 'CS002' then EventDt end) as [Charge - Written]
from case c
left join casestatushistory csh on c.caseid = csh.caseid
group by c.filenum,
c.casetype,
c.currentcasestatus
BTW, I would suggest just writing the statement out -- it won't take that long and it will out perform a dynamic sql approach. I'm not completely sure how you'd get your column names with dynamic sql either unless Phone and Written are in another column.
Try using a PIVOT. The SQL below should work -
--Select the pivot data into a temp table
SELECT c.caseID,
c.FileNum,
c.CaseType,
c.CurrentCaseStatus,
csh.EventDt,
cs.Description
INTO #StatusDates
FROM [Case] c
LEFT JOIN caseStatusHistory csh
ON csh.caseID = c.caseID
LEFT JOIN caseStatus cs
ON cs.Code = csh.CaseStatus
--From the pivot data, get the list of field names (assumes description field is the source for the field name)
DECLARE #statusDescriptions VARCHAR(MAX)
SET #statusDescriptions = ''
SELECT #statusDescriptions = COALESCE(#statusDescriptions+'[','') + Description
FROM (
SELECT DISTINCT Description
FROM #StatusDates
WHERE Description IS NOT NULL
) x
SET #statusDescriptions = REPLACE(#statusDescriptions, '[', '],[') + ']'
SET #statusDescriptions = SUBSTRING(#statusDescriptions, 3, LEN(#statusDescriptions))
--Create a SQL statement to pivot the data into the fields.
DECLARE #sql VARCHAR(MAX)
SET #SQL = '
SELECT *
FROM #StatusDates
PIVOT(MIN(EventDt)
FOR Description IN (' + #statusDescriptions + '))
AS PVTTable '
PRINT #sql
EXEC(#sql)
DROP TABLE #StatusDates

Join two select queries together

I have two select queries that I need to combine....
SELECT [DatapointID]
,[AssetID]
,[DatapointID]
,[SourceTag]
,'-' + [TimeStep] + [TimeStepValue] AS TimeStep
,[DataRetrievalInterval] + [DataRetrievalIntervalValue] AS [RetInterval]
,NULL AS DatapointDate
,NULL AS DatapointValue
,0 As DataFlagID
,DateADD(-1, d #SearchDateEnd) + #SearchTimeEnd DateDataGrabbed
,GetDate() DateTimeAddedtoDB
FROM [dbo].[tblTSS_Assets_Datapoints]
Where AssetID = 204
Select DatapointDate, SUM(DataPointValue) as DataPointValue From #temp
GROUP BY DatapointDate
ORDER BY DatapointDate
The first select query is what I want the end result to be however instead of NULL As the DatapointDate and DatapointValue I want the values from the #temp
How can I do this?
A join will combine the values from the two tables. In this case, there is not an obvious join key, so you would have a cross join:
SELECT [DatapointID], [AssetID], [DatapointID], [SourceTag],
'-' + [TimeStep] + [TimeStepValue] AS TimeStep,
[DataRetrievalInterval] + [DataRetrievalIntervalValue] AS [RetInterval],
d.DatePointDate, d.DatapointValue,
0 As DataFlagID,
DateADD(-1, d #SearchDateEnd) + #SearchTimeEnd DateDataGrabbed,
GetDate() DateTimeAddedtoDB
FROM [dbo].[tblTSS_Assets_Datapoints] cross join
(Select DatapointDate, SUM(DataPointValue) as DataPointValue From #temp
GROUP BY DatapointDate
) d
Where AssetID = 204
This, however, will multiply the number of rows, with one for each date. Do you have a specific rule for choosing one of the rows?