Transpose query creates nodes (SQL Server 2008) - sql

I finally found the query to execute to get all ids (comma separated) for one content in one row.
Following query did the trick:
You don't need to look at the query because it already does what it should do.
SELECT
taxonomy_item_id,
SUBSTRING(
(SELECT ', ' + CAST(taxonomy_id AS varchar) AS Expr1
FROM taxonomy_item_tbl AS t2
WHERE (t1.taxonomy_item_id = taxonomy_item_id) AND (taxonomy_language_id = 2067)
ORDER BY taxonomy_item_id, taxonomy_id FOR XML PATH('')
), 1, 1000) AS taxonomy_ids
FROM
taxonomy_item_tbl AS t1
WHERE
(taxonomy_language_id = 2067) AND (taxonomy_item_id = 180555)
GROUP BY
taxonomy_item_id
The only problem is the data result I get:
180555 | <Expr1>, 404</Expr1><Expr1>, 405</Expr1><Expr1>, 723</Expr1><Expr1>, 1086</Expr1><Expr1>, 1087</Expr1><Expr1>, 1118</Expr1><Expr1>, 1124</Expr1><Expr1>, 1126</Expr1>
I don't need the <Expr1> nodes. Is there a way to delete this? If I delete AS Expr1in the query then it is automatically added back
Thanks

If you don't want the <Expr1> - then just don't ask for it!
You have:
(SELECT ', ' + CAST(taxonomy_id AS varchar) AS Expr1
That AS Expr1 causes the <Expr1> to be added - so just don't have that expression there.
Try
SELECT
taxonomy_item_id,
SUBSTRING(
(SELECT ', ' + CAST(taxonomy_id AS VARCHAR)
FROM dbo.taxonomy_item_tbl AS t2
WHERE t1.taxonomy_item_id = taxonomy_item_id
AND taxonomy_language_id = 2067
ORDER BY taxonomy_item_id, taxonomy_id
FOR XML PATH('')
), 1, 1000) AS taxonomy_ids
FROM
dbo.taxonomy_item_tbl AS t1
WHERE
taxonomy_language_id = 2067
AND taxonomy_item_id = 180555
GROUP BY
taxonomy_item_id

Related

Concatening in a specific order given by a number

I have a table like this:
I want to concatenate the Product name in the given Product_order by ID.
Therefore, I should get something like: CC-TC-CA for ID 1.
you can use string_agg()- it'll work sql server 2016+
select id, string_Agg(product,',') as pname
from tablename
group by id
OR you can use stuff()
SELECT id,
STUFF((SELECT ',' + product
FROM tablename AS T1
WHERE T1.id = T2.id
FOR XML PATH('')), 1, 1, '')
FROM tablename AS T2
GROUP BY id
If you can use a stored procedure instead of a single query the += operator can do what you're looking for.
DECLARE #Product_order VARCHAR(100) = '';
SELECT #Product_order += Product + '-' FROM [table] WHERE id = 1 ORDER BY Product_Order;
SELECT SUBSTRING(#Product_order, 0, LEN(#Product_order));
Update: I've learned that returning multiple rows and using in an assignment in the select clause is unsupported behavior in SQL Server.

How to avoid duplicates in the STRING_AGG function SQL Server

I was testing a query in SQL in which I need to concatenate values ​​in the form of a comma-separated list, and it works, I just have the problem of duplicate values.
This is the query:
SELECT t0.id_marcas AS CodMarca,
t0.nombremarcas AS NombreMarca,
t0.imagenmarcas,
(SELECT String_agg((t2.name), ', ')
FROM exlcartu_devcit.store_to_cuisine t1
INNER JOIN exlcartu_devcit.cuisine t2
ON t1.cuisine_id = t2.cuisine_id
WHERE store_id = (SELECT TOP 1 store_id
FROM exlcartu_devcit.store
WHERE id_marcas = t0.id_marcas
AND status = 1)) AS Descripcion,
t0.logo,
t0.imagen,
(SELECT TOP 1 preparing_time
FROM exlcartu_devcit.store
WHERE id_marcas = t0.id_marcas
AND status = 1) AS Tiempo,
t0.orden,
(SELECT TOP 1 Avg(minimum_amount)
FROM exlcartu_devcit.store_delivery_zone
WHERE id_marcas = t0.id_marcas) AS MontoMinimo
FROM exlcartu_devcit.[marcas] t0
I thought the solution could be just adding a DISTINCT to the query to avoid repeated values ​​in this way ...
(SELECT STRING_AGG(DISTINCT (t2.name), ', ') AS Descripcion
But apparently the STRING_AGG() function does not support it, any idea how to avoid repeated values?
Simplest way is just select from select, like this:
with dups as (select 1 as one union all select 1 as one)
select string_agg(one, ', ') from (select distinct one from dups) q;
vs original
with dups as (select 1 as one union all select 1 as one)
select string_agg(one, ', ') from dups;

How to combine return results of query in one row

I have a table that save personnel code.
When I select from this table I get 3 rows result such as:
2129,3394,3508,3534
2129,3508
4056
I want when create select result combine in one row such as:
2129,3394,3508,3534,2129,3508,4056
or distinct value such as:
2129,3394,3508,3534,4056
You should ideally avoid storing CSV data at all in your tables. That being said, for your first result set we can try using STRING_AGG:
SELECT STRING_AGG(col, ',') AS output
FROM yourTable;
Your second requirement is more tricky, and we can try going through a table to remove duplicates:
WITH cte AS (
SELECT DISTINCT VALUE AS col
FROM yourTable t
CROSS APPLY STRING_SPLIT(t.col, ',')
)
SELECT STRING_AGG(col, ',') WITHIN GROUP (ORDER BY CAST(col AS INT)) AS output
FROM cte;
Demo
I solved this by using STUFF and FOR XML PATH:
SELECT
STUFF((SELECT ',' + US.remain_uncompleted
FROM Table_request US
WHERE exclusive = 0 AND reqact = 1 AND reqend = 0
FOR XML PATH('')), 1, 1, '')
Thank you Tim

Replace Matching Row String From Another Column

I have this table:
ID NewName OldName Link
1 NewName1 OldName1 OldName2|OldName3
2 NewName2 OldName2 OldName1|OldName3
3 NewName3 OldName3 OldName1|OldName2
What I want to happen is to change all the OldName on the Link column to the NewName. Like this:
ID NewName OldName Link
1 NewName1 OldName1 NewName2|NewName3
2 NewName2 OldName2 NewName1|NewName3
3 NewName3 OldName3 NewName1|NewName2
Can anyone suggest what's the best way to do this?
You are looking to Change the value of Link according OldNames to its with New Names:
First you will need to split your Link data delimited by |into row & then Join with Your Table
SELECT TTT.ID,
TTT.[NewName],
TTT.OldName,
[Link] = STUFF(
(
SELECT
'|'+[Link]
FROM
(
SELECT AA.ID,
AA.[NewName],
AA.OldName,
T.[NewName] [Link]
FROM
(
SELECT ID,
NewName,
OldName,
split.x.value('.', 'NVARCHAR(MAX)') DATA
FROM
(
SELECT ID,
NewName,
OldName,
CAST('<M>'+REPLACE(Link, '|', '</M><M>')+'</M>' AS XML) AS String
FROM <table_name>
) AS a
CROSS APPLY String.nodes('/M') AS split(x)
) AA
INNER JOIN <table_name> T ON T.OldName = AA.DATA
) TT
WHERE TT.ID = TTT.ID FOR XML PATH('')
), 1, 1, '')
FROM <table_name> TTT;
Result :
ID NewName OldName Link
1 NewName1 OldName1 NewName2|NewName3
2 NewName2 OldName2 NewName1|NewName3
3 NewName3 OldName3 NewName1|NewName2
MSSQL:
To store delimited-values from other column/other sources to a specific row, you may use FOR XML PATH, look at this SO thread:
UPDATE YourTable
SET Link = SUBSTRING(
(
SELECT '|' + T2.NewName
FROM YourTable T2
WHERE '|'+T2.Link+'|' LIKE '%|'+YourTable.OldName+'|%'
FOR XML PATH ('')
), 2, 1000);
MYSQL:
If you want to store delimited-values from other column/other sources to a specific row, you may use mysql GROUP_CONCAT function:
UPDATE table t1
SET Link = (
SELECT GROUP_CONCAT(t2.NewName SEPARATOR '|')
FROM table t2 WHERE FIND_IN_SET(t2.OldName, REPLACE(t1.Link, '|', ','))
)
I assumed that you want to replace any old values in the Link column with its new value.
See the results in action on dbfiddle.uk
If the Link column have only two names always, then we try self joining twice to match the respective new names which should be used for replacement. The join condition is ugly, but this is the price paid for storing denormalized data in your table.
WITH cte AS
(
SELECT t1.Link, t2.NewName AS NewNameLeft, t3.NewName AS NewNameRight
FROM yourTable t1
LEFT JOIN yourTable t2
ON SUBSTRING(t1.Link, 1, CHARINDEX('|', t1.Link) - 1) = t2.OldName
LEFT JOIN yourTable t3
ON SUBSTRING(t1.Link,
CHARINDEX('|', t1.Link) + 1,
LEN(t1.Link) - CHARINDEX('|', t1.Link)) = t3.OldName
)
UPDATE cte
SET Link = NewNameLeft + '|' + NewNameRight
WHERE NewNameLeft IS NOT NULL AND NewNameRight IS NOT NULL;
Note that this answer assumes that each old name appears only once in the table. I default to not doing an update unless both left and right new names are found.
I guess you just need REPLACE
select id, NewName, OldName, replace(link, 'OldName', 'NewName') Link
from your_data
and if you need to do it directly in table then use
update your_data
set link = replace(link, 'OldName', 'NewName')

Need your experience with query performance

i have been asked to find a way to improve the following query in order to make it faster. As is it takes about 15 min to run and it deletes no rows!
If i well understand, the query deletes all duplicates rows based on a multiple column key, and it keeps only the row with the greatest data value..but i'm not so sure...
DELETE FROM mytable F
WHERE f.f_elab = 'F'
AND EXISTS (SELECT 1 FROM mytable t
WHERE f.gldgj < t.gldgj
AND T.F_ELAB = 'F'
AND F.GLMCU = t.GLMCU
AND f.globj = t.globj
AND f.glsub = t.glsub
AND NVL(f.gmdl01,' ') = NVL(t.gmdl01,' ')
AND NVL(f.imitm,0) = NVL(t.imitm,0)
AND NVL(f.imlitm,' ') = NVL(t.imlitm,' ')
AND NVL(f.articolo_lunghezza_5,' ') = NVL(t.articolo_lunghezza_5,' ')
AND NVL(f.imdsc1,' ') = NVL(t.imdsc1,' ')
AND NVL(f.gmr022,' ') = NVL(t.gmr022,' ')
AND NVL(f.hfm,' ') = NVL(t.hfm,' ')
AND NVL(f.imglpt,' ') = NVL(t.imglpt,' ')
AND NVL(f.glsbl,' ') = NVL(t.glsbl,' ')
AND NVL(f.gldct,' ') = NVL(t.gldct,' ')
AND NVL(f.classe_coge,' ') = NVL(t.classe_coge,' ')
AND NVL(f.gldoc,0) = NVL(t.gldoc,0)
AND NVL(f.imsrp1,' ') = NVL(t.imsrp1,' ')
AND NVL(F.IMSRP4,' ') = NVL(t.IMSRP4,' ')
AND NVL(f.gllt,' ') = NVL(t.gllt,' ')
AND NVL(f.gmr030,' ') = NVL(t.gmr030,' ')
AND NVL(f.componente_costo,' ') = NVL(t.componente_costo,' ')
AND NVL(f.gmr033,' ') = NVL(t.gmr033,' ')
AND NVL(f.gmr034,' ') = NVL(t.gmr034,' ')
AND rownum<2);
Can someone help me on this? Thanks in advance.
I cannot really say if this will improve performance, but I would tackle this problem like so ...
DELETE FROM MYTABLE WHERE PRIMARY_KEY IN
(
SELECT MAX(PRIMARY_KEY) FROM MYTABLE
WHERE F_ELAB = 'F'
GROUP BY
GLMCU,
globj,
glsub,
gmdl01,
<... ETC ...>,
gmr034
HAVING COUNT(*) > 1
)
This assumes you HAVE a PK, of course. It also is only useful for duplicates, not triplicates (unless you run it more than once).
There is also a question as to the records you want to keep - first in, last in?
If you have no PK and it doesn't matter which record you wish to keep you can use RowID instead of PRIMARY_KEY
I finally found the solution, the query now runs in 4 seconds!
This is what i tried:
DELETE mytable WHERE ROWID IN
(
SELECT ROWID FROM
(
SELECT ROWID, ROW_NUMBER() OVER (PARTITION BY F_ELAB, GLMCU, globj, glsub, gmdl01, imitm, imlitm, articolo_lunghezza_5, imdsc1, gmr022, hfm, imglpt, glsbl, gldct , classe_coge , gldoc , imsrp1, IMSRP4, gllt, gmr030, componente_costo , gmr033, gmr034 ORDER BY gldgj DESC ) AS rn
FROM mytable F
WHERE f.f_elab = 'F'
)
WHERE rn > 1
)
This does exactly what the first query does! and it keeps only the record with the most recent date. The only doubt i still have is about all of those fields in the PARTITION BY argument. Do i have to use the NVL as it was in the first query? or it will work the same without that even if one or more fields have the null value?