T-SQL side-by-side coupling of data at the end - sql-server

In the following screenshot, I would like to merge the data in the YorumYapanAdsoyad column on a single line.
enter image description here
It should be this way;
8 | Fiat Linea 1.3 Multijet | Ahmet, Selami
12 | Vw Golf | Ertem, Selim
Thanks for the help ;)

Try this ,for earlier versions on SQL (2016 and down)
;WITH Tmp (UrunId, Araclar , YorumYapanSoyad) as
(
SELECT 8 , 'Fiat Line 1.3 Multijet' , 'Ahmet'
UNION ALL
SELECT 8 , 'Fiat Line 1.3 Multijet' , 'Selami'
UNION ALL
SELECT 12 , 'Vw Golf' , 'Ertem'
UNION ALL
SELECT 12 , 'Vw Golf' , 'Selim'
)
SELECT UrunId , Araclar ,
(SELECT STUFF(
(SELECT ', ' + YorumYapanSoyad
FROM Tmp b
WHERE B.Araclar = T.Araclar
AND b.UrunId = t.UrunId
FOR XML PATH (''),TYPE).value('.','nvarchar(max)'),1,2,'')
) YorumYapanSoyad
FROM Tmp t
GROUP BY UrunId , Araclar

Try this
DECLARE #Table TABLE (ID INT,Araclar varchar(100),YorumYapan varchar(20))
INSERT INTO #Table
SELECT 8 , 'Fiat Linea 1.3 Multijet' , 'Ahmet' UNION ALL
SELECT 8 , 'Fiat Linea 1.3 Multijet' , 'Selami' UNION ALL
SELECT 12 , 'Vw Golf' , 'Ertem' UNION ALL
SELECT 12 , 'Vw Golf' , 'Selim'
SELECT DISTINCT ID
,Araclar
,STUFF((SELECT ', '+YorumYapan
FROM #Table i WHERE i.ID=o.ID FOR XML PATH ('')),1,1,'') AS YorumYapan
FROM #Table o
Result
ID Araclar YorumYapan
------------------------------------------
8 Fiat Linea 1.3 Multijet Ahmet, Selami
12 Vw Golf Ertem, Selim

This is the recipe I use. As I don't know your table names, I made this example using sys.tables and sys.columns. Basically, the function STUFF is your friend here.
SELECT
t.name,
STUFF
(
(
SELECT ', ' + c.name
FROM sys.columns c
WHERE c.object_id = t.object_id
FOR XML PATH('')
),
1, /*string start*/
2, /*string length*/
'' /*replaceWith*/
)
FROM sys.tables t

Related

SQLSERVER Combine multiple lines into 1 row

I have the following tables:
Product_Order
Order_Num Order_Date
1 10/12/2017
2 10/31/2017
3 11/01/2017
Product_Order_Dtl
Order_Num Product_Desc
1 Toy_01
1 Toy_02
1 Toy_03
2 Toy_01
2 Toy_05
3 Toy_01
I am trying to update the Product Order Table to list all the products associated with that order into a new column called Product_List. Just like the following:
Product_Order
Order_Num Order_Date Product_List
1 10/12/2017 Toy_01, Toy_02, Toy_03
2 10/31/2017 Toy_01, Toy_05
3 11/01/2017 Toy_01
Is there a way to do that using an update statement? I am using a version of SQL 2012.
you can use below query
SELECT A.Order_Num, A.Order_Date, STUFF((SELECT ',' + Product_Desc
FROM Product_Order_Dtl C
where C.Order_Num=A.Order_Num
FOR XML PATH('')), 1, 1, '') AS Product_List
from Product_Order A
inner join Product_Order_Dtl B on A.Order_Num =B.Order_Num
group by A.Order_Num,A.Order_Date
This will do it:
SELECT
PO.Order_Num
, PO.Order_Date
,
STUFF
(
(
SELECT ', ' + POD.Product_Desc
FROM Product_Order_Dtl POD
WHERE POD.Order_Num = PO.Order_Num
ORDER BY POD.Product_Desc
FOR XML PATH ('')
), 1, 2, ''
) Product_List
FROM Product_Order PO

Dynamic Columns - SQL Server 2012

Having two tables, I want to convert some rows to columns. My database engine is Microsoft SQL Server. The image below illustrates my desired result.
Your question is not so clear, but it seems you want to use SQL PIVOT
Sample Data
DECLARE #tblModule TABLE(modId INT,name VARCHAR(200))
DECLARE #tblProfile TABLE(id INT,modId INT,profil VARCHAR(200))
INSERT INTO #tblModule
SELECT 1,'Manteniminento' UNION
SELECT 2 , 'Soporte'
INSERT INTO #tblProfile
SELECT 1,1,'Administrador' UNION
SELECT 2,2 , 'Empleado' UNION
SELECT 3,1 , 'Empleado' UNION
SELECT 4,1 , 'Empleado' UNION
SELECT 5,1 , 'Administrador' UNION
SELECT 6,1 , 'Administrador'
Main query
SELECT name,SUM([Administrador]) AS Administrador, SUM([Empleado]) AS Empleado
FROM
(SELECT id,p.modId,m.name,p.profil
FROM #tblProfile p
INNER JOIN #tblModule m ON m.modId = p.modId) AS SourceTable
PIVOT
(
COUNT(modId)
FOR profil IN ([Administrador], [Empleado])
) AS PivotTable
GROUP BY name
Result
name Administrador Empleado
Manteniminento 3 2
Soporte 0 1
I found the solution to what I needed. I share with you I made use of SQL STUFF:
SELECT A.codEmpresa
,A.nomEmpresa
,A.codSistema
,A.nomSistema
,A.codPerfil
,A.nomPerfil
,modulos = STUFF((SELECT DISTINCT ', ' + M.nomModulo
FROM smpseg.[0004] R
JOIN smpseg.[0014] SMOP
ON SMOP.codSistema = R.codSistema
AND SMOP.codModulo = R.codModulo
AND SMOP.codPerfil = A.codPerfil
AND SMOP.objDefault = CAST(1 AS BIT)
JOIN smpseg.[0011] O
ON O.codSistema = SMOP.codSistema
AND O.codModulo = SMOP.codModulo
AND O.codObjeto = SMOP.codObjeto
JOIN smpseg.[0010] M
ON M.codSistema = O.codSistema
AND M.codModulo = O.codModulo
WHERE R.codUsuario = #p_codUsuario
FOR XML PATH('')), 1, 2, '') FROM smpseg.[0004] A
JOIN smpseg.[0016] U
ON U.codUsuario = A.codUsuario

SQL Server Query for required result

I am using SQL Server with my application.
The Table data is as following :
And I want result in following format:
I have tried with split function but its not working properly.
Is it possible to get such a result.
Please suggest.
Thank you.
Try this. I did not manage to get a single Not Req, it is like this ("Not Req/Not Req").
drop table if exists dbo.TableB;
create table dbo.TableB (
OldSPC varchar(100)
, old_freq varchar(100)
, NewSPC varchar(100)
, new_freq varchar(100)
);
insert into dbo.TableB(OldSPC, old_freq, NewSPC, new_freq)
values ('ADH,BAP', '7,7', 'ADH,BAP', '7,7')
, ('Not Req', 'Not Req', 'ADH,BAP', '7,7')
, ('BAP,EXT,ADL', '35,7,42', 'BAP,EXT,BAP,ADL', '21,7,35,42');
select
tt1.OldSPCOldFreq
, tt2.NewSPCNewFreq
from (
select
t.OldSPC, t.old_freq, t.NewSPC, t.new_freq
, STRING_AGG(t1.value + '/' + t2.value, ',') OldSPCOldFreq
from dbo.TableB t
cross apply (
select
ROW_NUMBER () over (order by t.OldSPC) as Rbr
, ss.value
from string_split (t.OldSPC, ',') ss
) t1
cross apply (
select
ROW_NUMBER () over (order by t.old_freq) as Rbr
, ss.value
from string_split (t.old_freq, ',') ss
) t2
where t1.Rbr = t2.Rbr
group by t.OldSPC, t.old_freq, t.NewSPC, t.new_freq
) tt1
inner join (
select
t.OldSPC, t.old_freq, t.NewSPC, t.new_freq
, STRING_AGG(t3.value + '/' + t4.value, ',') NewSPCNewFreq
from dbo.TableB t
cross apply (
select
ROW_NUMBER () over (order by t.NewSPC) as Rbr
, ss.value
from string_split (t.NewSPC, ',') ss
) t3
cross apply (
select
ROW_NUMBER () over (order by t.new_freq) as Rbr
, ss.value
from string_split (t.new_freq, ',') ss
) t4
where t3.Rbr = t4.Rbr
group by t.OldSPC, t.old_freq, t.NewSPC, t.new_freq
) tt2 on tt1.OldSPC = tt2.OldSPC
and tt1.old_freq = tt2.old_freq
and tt1.NewSPC = tt2.NewSPC
and tt1.new_freq = tt2.new_freq
As mentioned in comments, it might be easier for you to do it on front end, but it could be done in SQL Server as well.
Partial Rextester Demo
I didn't replicate your whole scenario but got it for 2 columns. To do it first of all, you need a unique identifier for each row. I am using a sequence number (1,2,3...).
Now refer to this answer, which uses recursive subquery to split csv to rows. Then I used XML PATH to change columns back to csv.
This is the query which is doing it for OLD SPC and OLD FREQ.
;with tmp(SEQ,OldSPCItem,OldSPC,OLD_FREQ_item,OLD_FREQ) as (
select SEQ, LEFT(OldSPC, CHARINDEX(',',OldSPC+',')-1),
STUFF(OldSPC, 1, CHARINDEX(',',OldSPC+','), ''),
LEFT(OLD_FREQ, CHARINDEX(',',OLD_FREQ+',')-1),
STUFF(OLD_FREQ, 1, CHARINDEX(',',OLD_FREQ+','), '')
from table1
union all
select SEQ, LEFT(OldSPC, CHARINDEX(',',OldSPC+',')-1),
STUFF(OldSPC, 1, CHARINDEX(',',OldSPC+','), ''),
LEFT(OLD_FREQ, CHARINDEX(',',OLD_FREQ+',')-1),
STUFF(OLD_FREQ, 1, CHARINDEX(',',OLD_FREQ+','), '')
from tmp
where OldSPC > ''
)
select seq,STUFF( (SELECT ',' + CONCAT(OldSPCItem,'/',OLD_FREQ_item) FROM TMP I
WHERE I.seq = O.seq FOR XML PATH('')),1,1,'') OLD_SPC_OLD_FREQ
from tmp O
GROUP BY seq
;
It will give you this output
+-----+------------------+
| seq | OLD_SPC_OLD_FREQ |
+-----+------------------+
| 1 | ADH/7,BAP/9 |
| 2 | NOT REQ/NOT REQ |
+-----+------------------+
What do you have to do now
- Find a way to generate a sequence number to uniquely identify each row. If you can use any column, use that instead of SEQ.
Similarly add logic for NEW_SPC and NEW_FREQ. (just copy paste LEFT and STUFF like in OLD_FREQ and change it for NEW_SPC and NEW_FREQ.
Replace multiple NOT REQ/ with '', so you will get only one NOT REQ. You can do it with replace function.
If you face any issue/error while doing so, add it to the Rexterster Demo and share the URL, we will check that.

Change select with connect by prior from Oracle to SQL Server

Hello I have this part of a view in an Oracle database and I must change it on Microsoft Sql Server.
with V_LOCHIERARHY_N
(nr, nivel, location, parent, systemid, siteid, orgid, count_a, count_wo, children)
AS
SELECT LEVEL, LPAD (' ', 2 * (LEVEL - 1)) || l.LOCATION nivel,
LOCATION, PARENT, systemid, siteid, orgid,
(SELECT COUNT (a.ancestor)
FROM locancestor a
WHERE a.LOCATION = l.LOCATION AND a.siteid = l.siteid),
NVL (COUNT (w.wonum), 0)
FROM maximo.workorder w
WHERE ( w.reportdate >
TO_TIMESTAMP ('2006-06-19 00:00:01',
'YYYY-MM-DD HH24:MI:SS.FF'
)
AND w.istask = 0
AND w.worktype <> 'P'
AND w.LOCATION = l.LOCATION
)
AND w.status <> 'CAN'),
l.children
FROM lochierarchy l
START WITH l.LOCATION = 'StartPoint'
CONNECT BY PRIOR l.LOCATION = l.PARENT AND l.siteid = 'SiteTest'
What I need from this script is to return all the children of a given entry (the description of the children which can be found in locations table).
I have a table with next columns:
Location Parent Systemid Children Siteid Origid Lochierarchyid
A001 StartPoint Primary 2 SiteTest X 106372
A002 A001 Primary 2 SiteTest X 105472
A003 A002 Primary 0 SiteTest X 98654
A004 A002 Primary 1 SiteTest X 875543
A004B A004 Primary 0 SiteTest X 443216
B005 StartPoint Primary 0 SiteTest X 544321
For example for given entry A001 will return
A002
A003
A004
A004B
B005
I have made this view below but I don't know how to integrate it with the first one. Also it doesn't return me the list in the corectly order
Parent
Children 1 of parent
Children a of children 1
children b of children 1
children 2 of parent
children a1 of children 2 and so on.
WITH testCTE AS
(
SELECT l.parent, l.location as child, l.location, l.lochierarchyid
FROM lochierarchy l
where location='SecondLocation' --and siteid='SiteTest'
UNION ALL
SELECT c.Parent, l.parent, l.location, l.lochierarchyid
FROM lochierarchy l
INNER JOIN testCTE c ON l.parent = c.location
)
SELECT *
FROM testCTE c
order BY c.parent,child asc
;
Can please someone help me? :)
Following the query proposed by mathguy, modified for MSSQL (2012)
with
inputs ( location, parent ) as (
select 'A001' , 'StartPoint' union all
select 'A002' , 'A001' union all
select 'A003' , 'A002' union all
select 'A004' , 'A002' union all
select 'A004B', 'A004' union all
select 'B005' , 'StartPoint'
),
r (lvl, location, ord ) as (
select 1, location, CAST(location AS VARCHAR(400))
from inputs
where parent = 'StartPoint'
union all
select r.lvl + 1, i.location, CAST(r.location + '/' + i.location AS VARCHAR(400))
from r join inputs i on r.location = i.parent
)
select REPLICATE(' ', 2 * (lvl-1)) + location as location
from r
order by ord
;
Ouput:
location
-------------------------------------------------------------------
A001
A002
A003
A004
A004B
B005
Here is how you can do this (in Oracle, the only flavor I know) using a recursive query. "The web" reports SQL Server implements recursive queries as well, and with the same syntax (I believe all of this is SQL Standard compliant, so that's not surprising). Give it a try.
Instead of creating a table, I put all the test data in the first CTE. When you try this solution, delete the CTE named inputs first, and use your actual table name in the rest of the query.
with
inputs ( location, parent ) as (
select 'A001' , 'Downstream' from dual union all
select 'A002' , 'A001' from dual union all
select 'A003' , 'A002' from dual union all
select 'A004' , 'A002' from dual union all
select 'A004B', 'A004' from dual union all
select 'B005' , 'Downstream' from dual
),
r ( lvl, location ) as (
select 1, location
from inputs
where parent = 'Downstream'
union all
select r.lvl + 1, i.location
from r join inputs i on r.location = i.parent
)
search depth first by lvl set ord
select lpad(' ', 2 * (lvl-1), ' ') || location as location
from r
order by ord
;
LOCATION
--------------------
A001
A002
A003
A004
A004B
B005
6 rows selected.
ADDED: It seems SQL Server doesn't have the search depth/breadth first clause for recursive CTE's (or perhaps the syntax is different). In any case, here is a primitive "manual" implementation of the same:
with ( ......... ),
r ( lvl, location, ord ) as (
select 1, location, location
from inputs
where parent = 'Downstream'
union all
select r.lvl + 1, i.location, r.location || '/' || i.location
from r join inputs i on r.location = i.parent
)
select lpad(' ', 2 * (lvl-1), ' ') || location as location
from r
order by ord
;

Issue in complicated join

I have 4 tables
tbLicenceTypesX (2 Fields)
LicenceTypes
LicenceTypesX
tbLicenceTypesX (Contains data like)
1 - Medical Licence
2 - Property
3 - Casualty
4 - Trainning Licence
tbProduct (3 feilds)
Product
ProductX
CompanyId (F.K)
LicenceTypes(F.K)
tbProduct (Contains data like)
1 - T.V - 10 - 2
2 - A.C - 30 - 3
3 - Mobiles - 40 -4
tbLicence (3 feilds)
Licence
LicenceTypesNames
AgentId
tbLicence (Contains data like)
1 - Property, Casualty - 23
2 - Trainning Licence, Casualty - 34
Now I have to Fetch Product and ProductX from tbProduct whose LicenceTypes matches with Agent's Licence in tbLicence in a Company.
For e.g: I have to fetch T.V Whose Licence Types is 2("Property") and Company Id is 10 which should be assigned to Agent where Agent Id is 23 and Whose LicenceTypesNames should also contains "Property"
I want to fetch something like
#CompanyId int,
#AgentId int
As
SELECT p.ProductX,p.Product
from tbProduct p
inner join tbLicence l on p.LicenceTypes = l.LicenceTypesNames<its corresponding Id>
inner join tbProduct c on c.Product =p.Product
where
c.CompanyId=#CompanyId
and l.AgentId=#AgentId
Please help me!!!
You can use XML and CROSS APPLY to Split the comma separated values and JOIN with tbProduct. The LTRIM and RTRIM functions are used to trim the comma separated values if they have excessive empty space. The below code gives you the desired output.
DECLARE #CompanyId int = 30, #AgentId int = 23
;WITH CTE AS
(
SELECT AgentId, TCT.LicenceTypes FROM
(
SELECT AgentId, LTRIM(RTRIM(Split.XMLData.value('.', 'VARCHAR(100)'))) LicenceTypesNames FROM
(
SELECT AgentID, Cast ('<M>' + REPLACE(LicenceTypesNames, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM tbLicence
) AS XMLData
CROSS APPLY Data.nodes ('/M') AS Split(XMLData)
)
AS LTN
JOIN tbLicenceTypesX TCT ON LTN.LicenceTypesNames = tct.LicenceTypesX
)
SELECT p.ProductX,p.Product
FROM tbProduct P
JOIN CTE c on p.LicenceTypes = c.LicenceTypes
WHERE CompanyId = #CompanyId
AND AgentId = #AgentId
Sql Fiddle Demo

Resources