Ms Sql Trim comma , convert int , get data from another table - sql

I have varchar Id like below,
'1','2','3' etc..
I split as comma after that i convert Id to int
SELECT FIRSAT_PERSONELLER_ID,
cast(LTRIM(C.value('n[1]','VARCHAR(50)')) as int )AS item1
FROM (SELECT *,
X = CAST('<myxml><nodes><n>' + REPLACE(FIRSAT_PERSONELLER_ID,',','</n></nodes><nodes> <n>') +
'</n></nodes></myxml>' AS XML)
FROM FIRSATLAR
)t
CROSS APPLY X.nodes('/myxml/nodes') Cols (C)
Result is like below:
item1:
1
2
3
i want to match above "item1" Id with my User Table.I tried below code however it did not work.I want to see User Names.
SELECT username
FROM UserTable
Where UserId=item1Id(İtem1Id does not appear)
Also i am not sure Id value is int or varchar.
Instead of above query , what i need to write ?

tSQL would look like this:
SELECT username
FROM UserTable a
join
(SELECT FIRSAT_PERSONELLER_ID,
cast(LTRIM(C.value('n[1]','VARCHAR(50)')) as int )AS item1
FROM (SELECT *,
X = CAST('<myxml><nodes><n>' + REPLACE(FIRSAT_PERSONELLER_ID,',','</n></nodes><nodes> <n>') +
'</n></nodes></myxml>' AS XML)
FROM FIRSATLAR
)t
CROSS APPLY X.nodes('/myxml/nodes') Cols (C)
) b on a.UserId = b.item1
hope this helps.

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"}]

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.

Alphanumeric sort on nvarchar(50) column

I am trying to write a query that will return data sorted by an alphanumeric column, Code.
Below is my query:
SELECT *
FROM <<TableName>>
CROSS APPLY (SELECT PATINDEX('[A-Z, a-z][0-9]%', [Code]),
CHARINDEX('', [Code]) ) ca(PatPos, SpacePos)
CROSS APPLY (SELECT CONVERT(INTEGER, CASE WHEN ca.PatPos = 1 THEN
SUBSTRING([Code], 2,ISNULL(NULLIF(ca.SpacePos,0)-2, 8000)) ELSE NULL END),
CASE WHEN ca.PatPos = 1 THEN LEFT([Code],
ISNULL(NULLIF(ca.SpacePos,0)-0,1)) ELSE [Code] END) ca2(OrderBy2, OrderBy1)
WHERE [TypeID] = '1'
OUTPUT:
FFS1
FFS2
...
FFS12
FFS1.1
FFS1.2
...
FFS1.1E
FFS1.1R
...
FFS12.1
FFS12.2
FFS.12.1E
FFS12.1R
FFS12.2E
FFS12.2R
DESIRED OUTPUT:
FFS1
FFS1.1
FFS1.1E
FFS1.1R
....
FFS12
FFS12.1
FFS12.1E
FFS12.1R
What am I missing or overlooking?
EDIT:
Let me try to detail the table contents a little better. There are records for FFS1 - FFS12. Those are broken into X subs, i.e., FFS1.1 - FFS1.X to FFS12.1 - FFS12.X. The E and the R was not a typo, each sub record has two codes associated with it: FFS1.1E & FFS1.1R.
Additionally I tried using ORDER BY but it sorted as
FFS1
...
FFS10
FFS2
This will work for any count of parts separated by dots. The sorting is alphanumerical for each part separately.
DECLARE #YourValues TABLE(ID INT IDENTITY, SomeVal VARCHAR(100));
INSERT INTO #YourValues VALUES
('FFS1')
,('FFS2')
,('FFS12')
,('FFS1.1')
,('FFS1.2')
,('FFS1.1E')
,('FFS1.1R')
,('FFS12.1')
,('FFS12.2')
,('FFS.12.1E')
,('FFS12.1R')
,('FFS12.2E')
,('FFS12.2R');
--The query
WITH Splittable AS
(
SELECT ID
,SomeVal
,CAST(N'<x>' + REPLACE(SomeVal,'.','</x><x>') + N'</x>' AS XML) AS Casted
FROM #YourValues
)
,Parted AS
(
SELECT Splittable.*
,ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS PartNmbr
,A.part.value(N'text()[1]','nvarchar(max)') AS Part
FROM Splittable
CROSS APPLY Splittable.Casted.nodes(N'/x') AS A(part)
)
,AddSortCrit AS
(
SELECT ID
,SomeVal
,(SELECT LEFT(x.Part + REPLICATE(' ',10),10) AS [*]
FROM Parted AS x
WHERE x.ID=Parted.ID
ORDER BY PartNmbr
FOR XML PATH('')
) AS SortColumn
FROM Parted
GROUP BY ID,SomeVal
)
SELECT ID
,SomeVal
FROM AddSortCrit
ORDER BY SortColumn;
The result
ID SomeVal
10 FFS.12.1E
1 FFS1
4 FFS1.1
6 FFS1.1E
7 FFS1.1R
5 FFS1.2
3 FFS12
8 FFS12.1
11 FFS12.1R
9 FFS12.2
12 FFS12.2E
13 FFS12.2R
2 FFS2
Some explanation:
The first CTE will transform your codes to XML, which allows to address each part separately.
The second CTE returns each part toegther with a number.
The third CTE re-concatenates your code, but each part is padded to a length of 10 characters.
The final SELECT uses this new single-string-per-row in the ORDER BY.
Final hint:
This design is bad! You should not store these values in concatenated strings... Store them in separate columns and fiddle them together just for the output/presentation layer. Doing so avoids this rather ugly fiddle...

Regex matching the following Input in SQL Column

I have a SQL Column with the following values
ReportID
--------
19
19,20,21
20,19,21
20,21,19
119,21
1191,21
I need to match the the rows which have 19 as a value (i.e. reject last two rows)
Is there a better way to do this than the query used below ? (Using combined regex)
My Query:
SELECT *
FROM [StoreBI_Validation].[dbo].[PortalNotifications]
WHERE ReportID like '%,19,%'
or ReportID like '19'
or ReportID like '19,%'
or ReportID like '%,19'
Try this :
SELECT *
FROM Test
WHERE ','+ReportID+',' like '%,19,%'
SQL Fiddle
Or this :
SELECT DISTINCT reportid
FROM (
SELECT A.ReportID
,Split.a.value('.', 'VARCHAR(100)') AS Data
FROM (
SELECT ReportID
,CAST('<M>' + REPLACE(ReportID, ',', '</M><M>') + '</M>' AS XML) AS Data
FROM Test
) AS A
CROSS APPLY Data.nodes('/M') AS Split(a)
) B
WHERE Data = '19';
SELECT *
FROM [StoreBI_Validation].[dbo].[PortalNotifications]
WHERE CHARINDEX(',19,',ReportID)>0

SQL query for finding first missing sequence string (prefix+no)

T-SQL query for finding first missing sequence string (prefix+no)
Sequence can have a prefix + a continuing no.
ex sequence will be
ID
-------
AUTO_500
AUTO_501
AUTO_502
AUTO_504
AUTO_505
AUTO_506
AUTO_507
AUTO_508
So above the missing sequence is AUTO_503 or if there is no missing sequence then it must return next sequence.
Also starting no is to specified ex. 500 in this case and prefix can be null i.e. no prefix only numbers as sequence.
You could LEFT JOIN the id numbers on shifted(+1) values to find gaps in sequential order:
SELECT
MIN(a.offsetnum) AS first_missing_num
FROM
(
SELECT 500 AS offsetnum
UNION
SELECT CAST(REPLACE(id, 'AUTO_', '') AS INT) + 1
FROM tbl
) a
LEFT JOIN
(SELECT CAST(REPLACE(id, 'AUTO_', '') AS INT) AS idnum FROM tbl) b ON a.offsetnum = b.idnum
WHERE
a.offsetnum >= 500 AND b.idnum IS NULL
SQLFiddle Demo
Using a recursive CTE to dynamically generate the sequence between the min and max of the ID Numbers maybe over complicated things a bit but it seems to work -
LIVE ON FIDDLE
CREATE TABLE tbl (
id VARCHAR(55)
);
INSERT INTO tbl VALUES
('AUTO_500'),
('AUTO_501'),
('AUTO_502'),
('AUTO_504'),
('AUTO_505'),
('AUTO_506'),
('AUTO_507'),
('AUTO_508'),
('509');
;WITH
data_cte(id)AS
(SELECT [id] = CAST(REPLACE(id, 'AUTO_', '') AS INT) FROM tbl)
,maxmin_cte(minId, maxId)AS
(SELECT [minId] = min(id),[maxId] = max(id) FROM data_cte)
,recursive_cte(n) AS
(
SELECT [minId] n from maxmin_cte
UNION ALL
SELECT (1 + n) n FROM recursive_cte WHERE n < (SELECT [maxId] from maxmin_cte)
)
SELECT x.n
FROM
recursive_cte x
LEFT OUTER JOIN data_cte y ON
x.n = y.id
WHERE y.id IS NULL
Check this solution.Here you just need to add identity column.
CREATE TABLE tbl (
id VARCHAR(55),
idn int identity(0,1)
);
INSERT INTO tbl VALUES
('AUTO_500'),
('AUTO_501'),
('AUTO_502'),
('AUTO_504'),
('AUTO_505'),
('AUTO_506'),
('AUTO_507'),
('AUTO_508'),
('509');
SELECT min(idn+500) FROM tbl where 'AUTO_'+cast((idn+500) as varchar)<>id
try this:
with cte as(
select cast(REPLACE(id,'AUTO_','') as int)-500+1 [diff],ROW_NUMBER()
over(order by cast(REPLACE(id,'AUTO_','') as int)) [rnk] from tbl)
select top 1 'AUTO_'+cast(500+rnk as varchar(50)) [ID] from cte
where [diff]=[rnk]
order by rnk desc
SQL FIddle Demo
Had a similar situation, where we have R_Cds that were like this R01005
;with Active_R_CD (R_CD)
As
(
Select Distinct Cast(Replace(R_CD,'R', ' ') as Int)
from table
where stat = 1)
select Arc.R_CD + 1 as 'Gaps in R Code'
from Active_R_CD as Arc
left outer join Active_R_CD as r on ARC.R_CD + 1 = R.R_CD
where R.R_CD is null
order by 1