sql zero leading in comparing 2 record set - sql

I have a problem compare 2 set of data with and without leading zero.
In the Inventory_NBP, there is as 000000000000909120.
However, in PDM_Analysis, there exist only 909120 without the leading zero.
The current query below failed to retrieve any 000000000000909120 or 909120 as the "IN" condition is not met.
How do i modify the query below to fulfill my requirement?
sel * FROM Inventory_NBP.v_dmnd_rsrv_dpnd_rqr_mrp
WHERE plnt_id ='WA01'
and mtrl_id in('G29329-001', '000000000000909120', '13-0006-001')
and
(mtrl_id, plnt_id)
IN
( SELECT itm_cd, sap_plnt_cd
FROM PDM_Analysis.v_itm_plnt_extn
)

Do casting. This may solve your problem. Please check.
SELECT * FROM Inventory_NBP.v_dmnd_rsrv_dpnd_rqr_mrp
WHERE plnt_id ='WA01'
and mtrl_id in('G29329-001',CAST(CAST('000000000000909120' AS INT) AS VARCHAR(10)), '13-0006-001')
and
(mtrl_id, plnt_id)
IN
( SELECT itm_cd, sap_plnt_cd
FROM PDM_Analysis.v_itm_plnt_extn
)

Here's an example of how to match values regardless of leading zeros by padding (SQL Server 2008 syntax):
WITH T1
AS
(
SELECT *
FROM (
VALUES ('000000000000909120'),
('00000000099'),
('000000055'),
('22'),
('152')
) AS T (data_col)
),
T2
AS
(
SELECT *
FROM (
VALUES ('909120'),
('99'),
('00055'),
('0000000022'),
('152')
) AS T (data_col)
)
SELECT *
FROM T1 INNER JOIN T2
ON T1.data_col
= REPLICATE('0', LEN(T1.data_col) - LEN(T2.data_col))
+ T2.data_col
UNION
SELECT *
FROM T1 INNER JOIN T2
ON T2.data_col
= REPLICATE('0', LEN(T2.data_col) - LEN(T1.data_col))
+ T1.data_col;

Related

Modify T-SQL Query to include/exclude colums depending on other columns value

I have the below query, that I need some help modifying. In the below Query I get the number of columns that are not null and the percentage:
SELECT COUNT(v.col) as num_not_null, COUNT(v.col) * 1.0 / COUNT(*) * 100 as percent_not_null, COUNT(*) as toltalColsNeedsFilled
FROM EFP_EmploymentUser t
CROSS APPLY (VALUES (t.ITAdvicedFirst),
(t.ITAdvicedSecond),
(t.ITDepartmentDone),
(t.CFOAdvicedFirst),
(t.CFOInfoProvided),
(t.CFOAdvicedSecond),
(t.CFODone),
(t.EconomyAdviced),
(t.EconomyDone),
(t.AcademyAdviced),
(t.AcademyDone),
(t.PublicatorAdviced),
(t.PublicatorDone),
(t.PortraitAdviced),
(t.PortraitDone),
(t.WhoIsWhoAdviced),
(t.WhoIsWhoDone),
(t.BogportalAdviced),
(t.BogportalDone),
(t.KeyCardAdviced),
(t.KeyCardDone) ) v(col)
WHERE ID = '19';
This returns in the case of ID 19:
num_not_null percent_not_null toltalColsNeedsFilled
5 23.809523809500 21
But I need to check if the following columns in the same table (Publicator,Bogportal,Academy) are filled with value 'yes', and depending on that I need to include or exclude som of the columns from my above query:
i.e.: IF Academy = YES then include t.AcademyAdviced & t.AcademyDone
IF Publicator= YES then include t.PublicatorDone & t.PortraitAdviced
IF Bogportal = YES then include t.BogportalAdviced & t.BogportalDone
Can anyone help me how to modifying the query to achive this? :-)
Best Regards
Stig
You can use UNION ALL and WHERE predicates to decide which columns to add to the unpivot:
SELECT COUNT(v.col) as num_not_null, COUNT(v.col) * 1.0 / COUNT(*) * 100 as percent_not_null, COUNT(*) as toltalColsNeedsFilled
FROM EFP_EmploymentUser t
CROSS APPLY (
SELECT * FROM
( VALUES (t.ITAdvicedFirst),
(t.ITAdvicedSecond),
(t.ITDepartmentDone),
(t.CFOAdvicedFirst),
(t.CFOInfoProvided),
(t.CFOAdvicedSecond),
(t.CFODone),
(t.EconomyAdviced),
(t.EconomyDone),
(t.PortraitAdviced),
(t.PortraitDone),
(t.WhoIsWhoAdviced),
(t.WhoIsWhoDone),
(t.KeyCardAdviced),
(t.KeyCardDone) ) v(col)
UNION ALL
SELECT *
FROM (VALUES (t.AcademyAdviced), (t.AcademyDone) ) v(col)
WHERE t.Academy = 'YES'
UNION ALL
SELECT *
FROM (VALUES (t.PublicatorDone), (t.PortraitAdviced) ) v(col)
WHERE t.Publicator = 'YES'
UNION ALL
SELECT *
FROM (VALUES (t.BogportalAdviced), (t.BogportalDone ) ) v(col)
WHERE t.Bogportal = 'YES'
) v
WHERE t.ID = '19';

How to turn one column of numbers into one cell in SQL server? (Find all prime number smaller than 1000)

I'm required to write a query to print all prime numbers less than or equal to 1000. And I need to print the result into one single line and use the ampersand character as the separator (instead of a space). like this:
2&3&5&7&11&13
Here is my code (the datatype of Number is int so I need to change it to varchar so the ampersand character can show up in one cell with the Number):
with temp as
(select 2 as Number
union all
select Number + 1 from temp where Number<1000)
, temptwo as
(select * from temp t1
where NOT EXISTS
(select 1 from temp t2
where t1.Number > t2.Number
and t1.Number % t2.Number = 0))
, tempthree as
(select Cast(Number AS Varchar) as Number from temptwo)
select
STUFF((SELECT '&' + Number
FROM tempthree tt
WHERE tt.Number = t.Number
FOR XML PATH('')), 1, 1, '')
FROM tempthree t
OPTION (MAXRECURSION 0)
But it does not really work. I don't know what is the problem?
And up to this point it works well:
with temp as
(select 2 as Number
union all
select Number + 1 from temp where Number<1000)
, temptwo as
(select * from temp t1
where NOT EXISTS
(select 1 from temp t2
where t1.Number > t2.Number
and t1.Number % t2.Number = 0))
select Cast(Number AS Varchar) as Number from temptwo
OPTION (MAXRECURSION 0)
But it only prints out something like this:
2
3
5
7
11
13
...
But this is not I want. Can anyone help?
Your approach is OK to identify the prime numbers. You are just missing string aggregation.
Here is one option using string_agg(), available since SQL Server 2017:
with temp as (
select 1 num
union all
select num + 1 from temp where num < 1000
)
select string_agg(num, '&') within group(order by num) res
from temp t
where not exists (select 1 from temp t1 where t.num < t1.num and t.num % t1.num = 0)
option (maxrecursion 0)
Note that I eliminated the second cte, that is not really needed (you can put the not exists condition directly in the outer query).
If you are stuck with a version of SQL Server that doesn't support STRING_AGG, you need to use STUFF, but your syntax isn't quite right; it should look like:
with temp as
(select 2 as Number
union all
select Number + 1 from temp where Number<1000)
select STUFF((
SELECT '&' + Cast(Number AS Varchar)
FROM temp t1
where NOT EXISTS (select 1 from temp t2
where sqrt(t1.Number) >= t2.Number
and t1.Number % t2.Number = 0)
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
OPTION (MAXRECURSION 0)
Note I've made some optimisations, bring the parts of your second and third cte's into the STUFF, and improving the performance of the NOT EXISTS query by only looking at numbers up to the square root of the original number.
Output:
2&3&5&7&11&13&17&19&23&29&31&37&41&43&47&53&59&61&67&71&73&79&83&89&97&101&103&107&109&113&127&131&137&139&149&151&157&163&167&173&179&181&191&193&197&199&211&223&227&229&233&239&241&251&257&263&269&271&277&281&283&293&307&311&313&317&331&337&347&349&353&359&367&373&379&383&389&397&401&409&419&421&431&433&439&443&449&457&461&463&467&479&487&491&499&503&509&521&523&541&547&557&563&569&571&577&587&593&599&601&607&613&617&619&631&641&643&647&653&659&661&673&677&683&691&701&709&719&727&733&739&743&751&757&761&769&773&787&797&809&811&821&823&827&829&839&853&857&859&863&877&881&883&887&907&911&919&929&937&941&947&953&967&971&977&983&991&997
Demo on dbfiddle
You don't need the third CTE just for casting. Numbers are implicitly casted when used in concat().
But you need the subquery of the actual query to query all from the second CTE and concatenate it. The actual outer query needs to be FROM-less as you only want one row, not multiple, which you'd get if you selected from the second CTE.
The ampersand is a special character in XML and therefore encoded. An easy way to go around this is to initially use commas instead of ampersands and then use replace() to make the commas into ampersands.
WITH tempone
AS
(
SELECT 2 number
UNION ALL
SELECT number + 1
FROM tempone
WHERE number < 1000
),
temptwo
AS
(
SELECT *
FROM tempone t1
WHERE NOT EXISTS
(SELECT *
FROM tempone t2
WHERE t1.number > t2.number
AND t1.number % t2.number = 0)
)
SELECT replace(stuff((SELECT concat(',', tt.number)
FROM temptwo tt
FOR XML PATH('')), 1, 1, ''), ',', '&')
OPTION (MAXRECURSION 0);
db<>fiddle

can you set environmental variable to round numbers in SQL Server query?

I have a bunch of calculations in a SQL Server 2012 query, kind of like:
select T1_month
,a.some_value, b.value_to_compare,(select (some_value - value_to_compare)/value_to_compare*100 where value_to_compare != 0) percent_diff
from
(select T1_month
,sum(some_value) some_value
from T1
group by T1_month) a
join
(select T2_month
,sum(value_to_compare) value_to_compare
from T2
group by T2_month) b
on a.T1_month = b.T2_month
order by T1_month;
I used a round function here, but I need to add a lot more similar lines. Is there any way to just set a global variable to round all columns in one shot? Otherwise it's just a lot of leg work.
round((some_value - value_to_compare)/value_to_compare*100, 2)
I'll be pasting to Excel but it would be nice to round it in the source without having to use the round function so many times.
Here is a workaround, no need to type Round() function for every line:
SELECT 9.0 / 7 * 100 AS Direct_Query
CREATE TABLE #Table_1 (
[Column_1] [NUMERIC](18, 2) NULL
)
INSERT INTO #Table_1
SELECT 9.0/7 * 100
SELECT Column_1 AS Temp_Table_Formatted FROM #Table_1
Edit:
If you cannot use temp table, you can wrap your query with CTE then just Round() the result of CTE, which is pretty easy to do with help of a multiline editor like Sublime Text or VisualStudio Code:
WITH CTE_Result_To_Format
AS (
SELECT
T1_month
,a.some_value
,b.value_to_compare
,(
SELECT
(some_value - value_to_compare) / value_to_compare * 100
WHERE value_to_compare != 0
)
percent_diff
FROM (
SELECT
T1_month
,SUM(some_value) some_value
FROM T1
GROUP BY
T1_month
) a
JOIN (
SELECT
T2_month
,SUM(value_to_compare) value_to_compare
FROM T2
GROUP BY
T2_month
) b
ON a.T1_month = b.T2_month
)
SELECT
r.T1_month
,ROUND(r.some_value, 2) AS some_value
,ROUND(r.value_to_compare, 2) AS value_to_compare
,ROUND(r.percent_diff, 2) AS percent_diff
FROM CTE_Result_To_Format r
ORDER BY
r.T1_month

Get every combination of sort order and value of a csv

If I have a string with numbers separated by commas, like this:
Declare #string varchar(20) = '123,456,789'
And would like to return every possible combination + sort order of the values by doing this:
Select Combination FROM dbo.GetAllCombinations(#string)
Which would in result return this:
123
456
789
123,456
456,123
123,789
789,123
456,789
789,456
123,456,789
123,789,456
456,789,123
456,123,789
789,456,123
789,123,456
As you can see not only is every combination returned, but also each combination+sort order as well. The example shows only 3 values separated by commas, but should parse any amount--Recursive.
The logic needed would be somewhere in the realm of using a WITH CUBE statement, but the problem with using WITH CUBE (in a table structure instead of CSV of course), is that it won't shuffle the order of the values 123,456 456,123 etc., and will only provide each combination, which is only half of the battle.
Currently I have no idea what to try. If someone can provide some assistance it would be appreciated.
I use a User Defined Table-valued Function called split_delimiter that takes 2 values: the #delimited_string and the #delimiter_type.
CREATE FUNCTION [dbo].[split_delimiter](#delimited_string VARCHAR(8000), #delimiter_type CHAR(1))
RETURNS TABLE AS
RETURN
WITH cte10(num) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,cte100(num) AS
(
SELECT 1
FROM cte10 t1, cte10 t2
)
,cte10000(num) AS
(
SELECT 1
FROM cte100 t1, cte100 t2
)
,cte1(num) AS
(
SELECT TOP (ISNULL(DATALENGTH(#delimited_string),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM cte10000
)
,cte2(num) AS
(
SELECT 1
UNION ALL
SELECT t.num+1
FROM cte1 t
WHERE SUBSTRING(#delimited_string,t.num,1) = #delimiter_type
)
,cte3(num,[len]) AS
(
SELECT t.num
,ISNULL(NULLIF(CHARINDEX(#delimiter_type,#delimited_string,t.num),0)-t.num,8000)
FROM cte2 t
)
SELECT delimited_item_num = ROW_NUMBER() OVER(ORDER BY t.num)
,delimited_value = SUBSTRING(#delimited_string, t.num, t.[len])
FROM cte3 t;
Using that I was able to parse the CSV to a table and join it back to itself multiple times and use WITH ROLLUP to get the permutations you are looking for.
WITH Numbers as
(
SELECT delimited_value
FROM dbo.split_delimiter('123,456,789',',')
)
SELECT CAST(Nums1.delimited_value AS VARCHAR)
,ISNULL(CAST(Nums2.delimited_value AS VARCHAR),'')
,ISNULL(CAST(Nums3.delimited_value AS VARCHAR),'')
,CAST(Nums4.delimited_value AS VARCHAR)
FROM Numbers as Nums1
LEFT JOIN Numbers as Nums2
ON Nums2.delimited_value not in (Nums1.delimited_value)
LEFT JOIN Numbers as Nums3
ON Nums3.delimited_value not in (Nums1.delimited_value, Nums2.delimited_value)
LEFT JOIN Numbers as Nums4
ON Nums4.delimited_value not in (Nums1.delimited_value, Nums2.delimited_value, Nums3.delimited_value)
GROUP BY CAST(Nums1.delimited_value AS VARCHAR)
,ISNULL(CAST(Nums2.delimited_value AS VARCHAR),'')
,ISNULL(CAST(Nums3.delimited_value AS VARCHAR),'')
,CAST(Nums4.delimited_value AS VARCHAR) WITH ROLLUP
If you will potentially have more than 3 or 4, you'll want to expand your code accordingly.

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