How to aggregate/concate strings with no duplicates in SQL Server 2019 - sql

I am very new to SQL Server and it stucks in one task related to the aggregation of data. I tried to put all information on the screen attached. Is there anyone that could support it? My current code is below, but it does not work (duplicates...). Many thanks in advance!
select distinct
material,
plant,
STRING_AGG (exceptions, ';' ),
STRING_AGG (preferential_country, ';' )
from grs
GROUP BY material, plant

Sorry, I misunderstood part of your question. This is a bit messy, but I created a function to remove the duplicates.
CREATE FUNCTION remove_duplicate (#str varchar(100))
RETURNS varchar(100) AS
BEGIN
DECLARE #result varchar(100)
SET #result = (SELECT STRING_AGG(ta.value,';') from(
SELECT DISTINCT value FROM STRING_SPLIT(#str ,';')
)as ta)
RETURN #result
END;
This is the query to create the output table where the exceptions are group together but there will be duplicates
SELECT distinct plant,
material,
CASE WHEN count( distinct(preferential_country)) > 1 THEN 'QU'
ELSE MAX(preferential_country)
END AS preferential_country,
STRING_AGG(exceptions,';') as exceptions
into new_table
FROM tableA
group by plant, material
order by plant
Lastly, you just need to use the function to remove the duplicates.
SELECT plant, material, dbo.remove_duplicate(exceptions) as exceptions from new_table
output:
plant material exceptions
plant_1 Material_1 EU01;EU02;EU03;EU05
plant_1 Material_2 EU01
plant_2 Material_1 NULL
I couldn't get it to work in db fiddle but it's working on SSMS
db fiddle

Related

Using a scalar variable inside a CTE

I am reviewing someone else's code but I've hit a wall. When I try to execute the provided script I get the following error:
Must declare the scalar variable "#userId".
I tried to remove the semicolon on line 2 just to try things but that give me the following error:
Incorrect syntax near the keyword 'with'. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon.
I'm very confused by this because this exact piece of code works on machines of others, but not on mine. I know there are other ways to write this query but I need to get this to work. Is there any way to make the variable work as intended in this script without rewriting the whole thing?
I'm using Microsoft SQL Server 2019 (RTM-CU8) (KB4577194) - 15.0.4073.23 (X64) on Ubuntu 18.04.4 LTS.
DECLARE #userId int
SET #userId =:user_id;
WITH bidsplacedtotal AS (
SELECT amount, user_id, auction_id
FROM bids WHERE user_id = #userId
)
,bidsreceivedtotal AS (
SELECT amount, user_id, auction_id
FROM bids WHERE auction_id IN
(SELECT id FROM auctions WHERE user_id = #userId)
)
SELECT COUNT(amount) FROM bidsplacedtotal) AS placed_total
UNION
SELECT COUNT(amount) FROM bidsreceivedtotal) AS received_total
Try this code to see if it works:
DECLARE #userId int
SELECT #userId = 2091
;WITH bidsplacedtotal AS (
SELECT amount, user_id, auction_id
FROM bids WHERE user_id = #userId
)
,bidsreceivedtotal AS (
SELECT amount, user_id, auction_id
FROM bids WHERE auction_id IN
(SELECT id FROM auctions WHERE user_id = #userId)
)
SELECT COUNT(amount) as CountAmount FROM bidsplacedtotal) AS placed_total
UNION
SELECT COUNT(amount) as CountAmount FROM bidsreceivedtotal) AS received_total

QSqlQuery Not Executing When Using Table Variable

I am using Python 3 and PyQt 5 to execute a query that includes a table variable. My other queries work, but this specific one is causing me issues. The query is:
declare #Temp table
(
SKU varchar(25),
Lines int
)
insert into #Temp
SELECT convert(varchar, [Sku]) as [SKU]
,count([Order Number]) as [Lines]
from [Database].dbo.[Table Name]
GROUP BY [Sku]
ORDER BY [LINES]
Select RANK() OVER(Order by Lines Desc) / (Select Convert(float,Count(*)) from #Temp) as [CUM PERCENT SKU]
,sum(Lines) Over(Order by Lines Desc) / convert(float,sum(Lines) Over()) as [CUM PERCENT LINES]
from #Temp
Order By [Lines] DESC
I replaced the Database name and the Table name, but the rest of the text is the exact query.
Executing the above in SQL Server 2012 works perfectly. Is there a limitation to QSql that I don't know about?
Thank you in advance!
After a bit more research, it turns out that you need to use prepare() when you are trying to create a table (apparently even a temporary one).
I'm posting the answer in case anyone else has the same issue and doesn't feel like going through the C++ StackOverflow answers.
query = QSqlQuery()
query.prepare(*query text here*)
query.exec_()

Multi row to a row sql

I have a table as bellow:
I want query to print output as bellow:
Note: Please, do not downvote. I know the rules of posting answers, but for such of questions there's no chance to post short answer. I posted it only to provide help for those who want to find out how to achieve that, but does not expect ready-to-use solution.
I'd suggest to read these articles:
PIVOT on two or more fields in SQL Server
Pivoting on multiple columns - SQL Server
Pivot two or more columns in SQL Server 2005
At first UNPIVOT then PIVOT. If number of rows for each Pod_ID is not always equal 3 then you need to use dynamic SQL. The basic sample:
SELECT *
FROM (
SELECT Pod_ID,
Purs + CASE WHEN RN-1 = 0 THEN '' ELSE CAST(RN-1 as nvarchar(10)) END as Purs,
[Values]
FROM (
SELECT Pod_ID,
Pur_Qty, --All columns that will be UNPIVOTed must be same datatype
Pur_Price,
CAST(ETD_Date as int) ETD_Date, -- that is why I cast date to int
ROW_NUMBER() OVER (ORDER BY (SELECT 1)) as RN
FROM YourTable
) as p1
UNPIVOT (
[Values] FOR [Purs] IN(Pur_Qty, Pur_Price, ETD_Date)
) as unpvt
) as p2
PIVOT (
MAX([Values]) FOR Purs IN (Pur_Qty,Pur_Price,ETD_Date,Pur_Qty1,Pur_Price1,ETD_Date1,Pur_Qty2,Pur_Price2,ETD_Date2)
) as pvt
Will bring you:
Pod_ID Pur_Qty Pur_Price ETD_Date Pur_Qty1 Pur_Price1 ETD_Date1 Pur_Qty2 Pur_Price2 ETD_Date2
F8E2F614-75BC-4E46-B7F8-18C7FC4E5397 24 22 20160820 400 33 20160905 50 44 20160830

PLSQL more than single row returned issue in ID field

I have an issue with the query below, in the main SELECT the value of
ENTITY_ID cannot be retrieved, as I'm using LIKE I get more than a single result back.
How can I overcome this?
If I place an inner SELECT such as:
(
SELECT
SEC_NN_SERVER_T.SRV_ID
FROM
SEC_NN_SERVER_T
WHERE
UPPER(SEC_NN_SERVER_T.SRV_NAME) LIKE UPPER('%gen%') ) AS ENTITY_ID,
I get the same error:
"ORA-01427: single-row subquery returns more than one row".
He is the full query:
SELECT DISTINCT
SEC_USER.USR_ID AS USR_ID,
SEC_USER.USR_FIRST_NAME AS USR_FIRST_NAME,
SEC_USER.USR_LAST_NAME AS USR_LAST_NAME,
SEC_USER_PRIV.ROLE_ID AS SYSTEM_ROLE_ID,
21 AS ENTITY_TYP_CODE,
(
SELECT
SEC_NN_SERVER_T.SRV_ID
FROM
SEC_NN_SERVER_T
WHERE
UPPER(SEC_NN_SERVER_T.SRV_NAME) LIKE UPPER('%gen%') ) AS ENTITY_ID
FROM
SEC_USER_PRIV,
SEC_USER
WHERE
SEC_USER.USR_ID = SEC_USER_PRIV.USR_ID
AND ((
SEC_USER_PRIV.ENTITY_TYP_CODE = 21
AND SEC_USER_PRIV.ENTITY_ID IN (
(
SELECT
SERVER_T.SRV_ID
FROM
SERVER_T
WHERE
UPPER(SERVER_T.SRV_NAME) LIKE UPPER('%gen%') ))))
Please assist thanks in advance.
By repeating the subquery from your where clause in your select you destroy the coupling between SEC_USER_PRIV.ENTITY_ID and the subquery. Subqueries in the SELECT part should always return only one value, because the select constructs the row to be returned. I expect your problem will be solved by simply including SEC_USER_PRIV.ENTITY_ID instead of the subquery.
What part of the error message do you not understand? Your subquery is returning more than one row. You can fix the error by using rownum or aggregation:
(SELECT MAX(SEC_NN_SERVER_T.SRV_ID)
FROM SEC_NN_SERVER_T
WHERE UPPER(SEC_NN_SERVER_T.SRV_NAME) LIKE UPPER('%gen%')
) as ENTITY_ID
or perhaps:
(SELECT LISTAGG(SEC_NN_SERVER_T.SRV_ID, ', ') WITHIN GROUP (ORDER BY SEC_NN_SERVER_T.SRV_ID)
FROM SEC_NN_SERVER_T
WHERE UPPER(SEC_NN_SERVER_T.SRV_NAME) LIKE UPPER('%gen%')
) as ENTITY_IDS
However, this might not be what you really want. You need to review the logic of what you are doing.
you can try the query below
SELECT DISTINCT
SEC_USER.USR_ID AS USR_ID,
SEC_USER.USR_FIRST_NAME AS USR_FIRST_NAME,
SEC_USER.USR_LAST_NAME AS USR_LAST_NAME,
SEC_USER_PRIV.ROLE_ID AS SYSTEM_ROLE_ID,
21 AS ENTITY_TYP_CODE,
SEC_NN_SERVER_T.SRV_ID AS ENTITY_ID
FROM SEC_USER_PRIV inner join
SEC_USER on SEC_USER.USR_ID = SEC_USER_PRIV.USR_ID inner join
SERVER_T on SEC_USER_PRIV.ENTITY_ID = SERVER_T.SRV_ID
and UPPER(SERVER_T.SRV_NAME) LIKE '%GEN%'
where SEC_USER_PRIV.ENTITY_TYP_CODE = 21
Looking at the comments on above answers, and guessing as it is not clear what you want to do, you might like to investigate cursors. A generic example below.
Declare
cursor c_test is
SELECT SEC_NN_SERVER_T.SRV_ID
FROM SEC_NN_SERVER_T
WHERE UPPER(SEC_NN_SERVER_T.SRV_NAME) LIKE UPPER('%gen%') ) AS ENTITY_ID
begin
for v_row in c_test loop
your logic for each ID here.
end loop;
end;

Inserting and transforming data from SQL table

I have a question which has been bugging me for a couple of days now. I have a table with:
Date
ID
Status_ID
Start_Time
End_Time
Status_Time(seconds) (How ling they were in a certain status, in seconds)
I want to put this data in another table, that has the Status_ID grouped up as columns. This table has columns like this:
Date
ID
Lunch (in seconds)
Break(in seconds)
Vacation, (in seconds) etc.
So, Status_ID 2 and 3 might be grouped under vacation, Status_ID 1 lunch, etc.
I have thought of doing a Case nested in a while loop, to go through every row to insert into my other table. However, I cannot wrap my head around inserting this data from Status_ID in rows, to columns that they are now grouped by.
There's no need for a WHILE loop.
SELECT
date,
id,
SUM(CASE WHEN status_id = 1 THEN status_time ELSE 0 END) AS lunch,
SUM(CASE WHEN status_id = 2 THEN status_time ELSE 0 END) AS break,
SUM(CASE WHEN status_id = 3 THEN status_time ELSE 0 END) AS vacation
FROM
My_Table
GROUP BY
date,
id
Also, keeping the status_time in the table is a mistake (unless it's a non-persistent, calculated column). You are effectively storing the same data in two places in the database, which is going to end up resulting in inconsistencies. The same goes for pushing this data into another table with times broken out by status type. Don't create a new table to hold the data, use the query to get the data when you need it.
This type of query (that transpose values from rows into columns) is named pivot query (SQL Server) or crosstab (Access).
There is two types of pivot queries (generally speaking):
With a fixed number of columns.
With a dynamic number of columns.
SQL Server support both types but:
Database Engine (query language: T-SQL) support directly only pivot
queries with a fixed number of columns(1) and indirectly (2)
Analysis Services (query language: MDX) support directly both types (1 & 2).
Also, you can query(MDX) Analysis Service data sources from T-SQL using OPENQUERY/OPENROWSET functions or using a linked server with four-part names.
T-SQL (only) solutions:
For the first type (1), starting with SQL Server 2005 you can use the PIVOT operator:
SELECT pvt.*
FROM
(
SELECT Date, Id, Status_ID, Status_Time
FROM Table
) src
PIVOT ( SUM(src.Status_Time) FOR src.Status_ID IN ([1], [2], [3]) ) pvt
or
SELECT pvt.Date, pvt.Id, pvt.[1] AS Lunch, pvt.[2] AS [Break], pvt.[3] Vacation
FROM
(
SELECT Date, Id, Status_ID, Status_Time
FROM Table
) src
PIVOT ( SUM(src.Status_Time) FOR src.Status_ID IN ([1], [2], [3]) ) pvt
For a dynamic number of columns (2), T-SQL offers only an indirect solution: dynamic queries. First, you must find all distinct values from Status_ID and the next move is to build the final query:
DECLARE #SQLStatement NVARCHAR(4000)
,#PivotValues NVARCHAR(4000);
SET #PivotValues = '';
SELECT #PivotValues = #PivotValues + ',' + QUOTENAME(src.Status_ID)
FROM
(
SELECT DISTINCT Status_ID
FROM Table
) src;
SET #PivotValues = SUBSTRING(#PivotValues,2,4000);
SELECT #SQLStatement =
'SELECT pvt.*
FROM
(
SELECT Date, Id, Status_ID, Status_Time
FROM Table
) src
PIVOT ( SUM(src.Status_Time) FOR src.Status_ID IN ('+#PivotValues+') ) pvt';
EXECUTE sp_executesql #SQLStatement;