Sequence number between string in sql - sql

I have a stored procedure like this
declare #Tmp varchar(60)
declare #Hasil varchar(60)
declare #PFID varchar(50)
declare #CntPFID int
declare #PrevPFID varchar(60)
DECLARE #CheckLetter CHAR(5)
set #PFID = 'PF-FB/ALL/009/MKX/VI/16'
set #CheckLetter = (UPPER(RIGHT((CAST(SUBSTRING(#PFID, 10, 4) AS VARCHAR(5))), 3)))
select #CntPFID = count(pfid)
from pf
where pfid like '%'+ right(#PFID, 9)
and pfid like ''+ left(#PFID, 13) +'%'
if #CntPFID = 1
begin
set #Tmp = (UPPER(RIGHT((CAST(SUBSTRING(#PFID, 10, 4) AS VARCHAR(5))), 3))) + '-' + '01'
set #Hasil = replace(#PFID, replace(#CheckLetter, ' ', ''), #Tmp)
end
else
begin
set #Tmp = (UPPER(RIGHT((CAST(SUBSTRING(#PFID, 10, 4) AS VARCHAR(5))), 3))) + '-0' + cast(#CntPFID as varchar(3))
set #Hasil = replace(#PFID, replace(#CheckLetter, ' ', ''), #Tmp)
end
select #Hasil
I was stuck when the record data already reach 'PF-FB/ALL/009-09/MKX/VI/16' the next number becoming PF-FB/ALL/009-010/MKX/VI/16 (there is three digits = 010) while I want it will be PF-FB/ALL/009-10/MKX/VI/16 (2 digits running).
Is there any dynamically way without using condition else if > 9 ... ?

The expression you need to change: '-0' + cast(#CntPFID as varchar(3)), try this way:
declare #CntPFID int;
set #CntPFID = 9;
select '-' + right('00'+ cast(#CntPFID as varchar(3)),2)
set #CntPFID = 11;
select '-' + right('00'+ cast(#CntPFID as varchar(3)),2)

Related

Year number range formatting

I have these year number ranges
1993-1997
1923-1935
1998-2015
I'm trying to produce this shortened version of these year ranges.
1993-7
1923-35
1998-2015
So far my query looks like this. But its not working on the 2nd and 3rd samples, 1923-1935, and 1998-2015.
declare #bookyear varchar(50)
declare #year1 char(4)
declare #year2 char(4)
set #bookyear = '1993-1997'
set #year1 = substring(#bookyear, 1, charindex('-', #bookyear)-1)
set #year2 = substring(#bookyear, charindex('-', #bookyear) + 1, len(#bookyear))
select cast(#year1 as varchar(50)) + '-'+ substring(#year2, 4, 1)
Note: Year is always in 4 digits.
I am assuming you want a single digit year if its within the same decade, and double digit year when its a different decade. In which case use a case statement to compare the decade component and then display the appropriate number of digits e.g.
declare #bookyear varchar(50), #year1 char(4), #year2 char(4);
set #bookyear = '1993-1997';
set #year1 = substring(#bookyear, 1, charindex('-', #bookyear)-1);
set #year2 = substring(#bookyear, charindex('-', #bookyear) + 1, len(#bookyear));
select cast(#year1 as varchar(50)) + '-'
+ case when substring(#Year1,1,3) = substring(#Year2,1,3) then substring(#year2, 4, 1)
when substring(#Year1,1,2) = substring(#Year2,1,2) then substring(#year2, 3, 2)
else substring(#year2, 1, 4) end;
Assuming your input strings will always have same length i.e. 9 characters
drop table if exists t
create table t (d varchar(9))
insert into t values
('1993-1997')
,('1923-1935')
,('1998-2015')
,('2095-2115')
SQLFIDDLE
select d
, case
when LEFT(d, 3) = LEFT(RIGHT(d , 4), 3) then LEFT(d, 5) + RIGHT(d, 1)
when LEFT(d, 2) = LEFT(RIGHT(d , 4), 2) then LEFT(d, 5) + RIGHT(d, 2)
when LEFT(d, 1) = LEFT(RIGHT(d , 4), 1) then LEFT(d, 5) + RIGHT(d, 3)
ELSE d
end
FROM t
There are actually 2 ways to address this.
Looking for the same from the right.
Or looking for differences from the left.
Example snippet:
declare #bookyear varchar(9);
set #bookyear = '1993-1997';
--
-- looking for different digits from left to right
--
set #bookyear = left(#bookyear,5) +
case
when left(#bookyear,1) != substring(#bookyear,6,1) then right(#bookyear,4)
when left(#bookyear,2) != substring(#bookyear,6,2) then right(#bookyear,3)
when left(#bookyear,3) != substring(#bookyear,6,3) then right(#bookyear,2)
else right(#bookyear,1)
end;
select #bookyear as bookyear1;
-- reset variable
set #bookyear = '1993-1997';
--
-- looking for same digits from right to left
--
set #bookyear = left(#bookyear,5) +
case
when left(#bookyear,3) = substring(#bookyear,6,3) then substring(#bookyear,9,1)
when left(#bookyear,2) = substring(#bookyear,6,2) then substring(#bookyear,8,2)
when left(#bookyear,1) = substring(#bookyear,6,1) then substring(#bookyear,7,3)
else substring(#bookyear,6,4)
end;
select #bookyear as bookyear2;
A test snippet using a table variable:
declare #Test table (bookyear varchar(9));
insert into #Test (bookyear) values
('1993-1997'),
('1923-1935'),
('1998-2015'),
('2095-2115');
select
bookyear,
left(bookyear,5) +
case
when left(bookyear,1) != substring(bookyear,6,1) then right(bookyear,4)
when left(bookyear,2) != substring(bookyear,6,2) then right(bookyear,3)
when left(bookyear,3) != substring(bookyear,6,3) then right(bookyear,2)
else right(bookyear,1)
end as bookyear1,
left(bookyear,5) +
case
when left(bookyear,3) = substring(bookyear,6,3) then substring(bookyear,9,1)
when left(bookyear,2) = substring(bookyear,6,2) then substring(bookyear,8,2)
when left(bookyear,1) = substring(bookyear,6,1) then substring(bookyear,7,3)
else substring(bookyear,6,4)
end as bookyear2
from #Test;
Returns:
bookyear bookyear1 bookyear2
1993-1997 1993-7 1993-7
1923-1935 1923-35 1923-35
1998-2015 1998-2015 1998-2015
2095-2115 2095-115 2095-115
A test on rextester here

SQL Server : prevent output of tablename with date later then today

I am trying to display data with 11 months from 11 tables. Each table containing a different months data. The table name contains the date of each table. At the moment my code works in a way that a person has to input a date such as 201404 then it will display all months from 201404 right up to 201503. I need to put a check in place so that if the person types in 201507 it only throws out 201507 up to 201510 as the remaining months do not exists as yet.
This is my code:
alter PROCEDURE stp3
#FirstTableMonth int =0,
#EndMonth datetime
AS
DECLARE
#LinkedServerName sysname = 'SERVER1',
#left int = 0,
#right int= 0,
#STRING VARCHAR(6),
#monthex int = 12,
#yearex int,
#yearstring int,
#DynamicSQL nvarchar(max) = '',
#DynamicSQL2 nvarchar(max) = '',
#OpenQuerySql nvarchar(max),
#Table_Name sysname,
#Table_Name2 sysname,
#TableMonth int,
#TableMonth2 int ,
#CurrentMonth int = 0,
#NextYearMonth int = 1,
#part2 nvarchar(max) = '',
#TwelfthMonth int = 0;
SET #FirstTableMonth= CAST(#FirstTableMonth AS VARCHAR(6))
set #left = cast(left(#FirstTableMonth,4) +1 as varchar(max))
set #right = right(#FirstTableMonth,2) - 1
set #monthex = 11
set #yearex = cast(left(#FirstTableMonth,4) as varchar(max))
set #yearstring = case when right(#FirstTableMonth,2) = '01' then left(#FirstTableMonth,4) + RIGHT( #monthex + LTRIM( RTRIM( right(#FirstTableMonth,2) ) ), 6 ) else #left end
SET #STRING =
case when right(#FirstTableMonth,2) = '01' then #yearstring
when #right < 10 then CAST(#left AS VARCHAR(4)) + RIGHT( '0' + LTRIM( RTRIM( #right ) ), 6 )
else CAST(#left AS VARCHAR(4)) + RIGHT( LTRIM( RTRIM( #right ) ), 6 ) end
WHILE #CurrentMonth < 11 AND #EndMonth < getdate()
BEGIN
SELECT #TableMonth = CASE WHEN (#FirstTableMonth + #CurrentMonth) % 100 < 13 THEN
#FirstTableMonth + #CurrentMonth
ELSE
#FirstTableMonth + 100 - (#FirstTableMonth % 100) + #NextYearMonth
END,
#NextYearMonth = CASE WHEN (#FirstTableMonth + #CurrentMonth) % 100 < 13 THEN
#NextYearMonth
ELSE
#NextYearMonth + 1
END,
#Table_Name = 'XX_'+CAST(#TableMonth as varchar)+'_T' ,
#TableMonth2 = #TableMonth,
#Table_Name2 = 'XX_'+CAST(#TableMonth2 as varchar)+'_T' ,
#DynamicSQL = #DynamicSQL +
'SELECT
*
FROM '+ #Table_Name + '
'+ CASE WHEN #CurrentMonth < 10 THEN ' UNION ALL ' ELSE '' END ,
#DynamicSQL2 = #DynamicSQL2 +
'SELECT
*
FROM '+ #Table_Name2 + '
'
SET #CurrentMonth = #CurrentMonth + 1
IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL BEGIN DROP TABLE #TEMP END
IF OBJECT_ID('tempdb..#Unioned') IS NOT NULL BEGIN DROP TABLE #Unioned END
--last months snapshot
SELECT
*
INTO #UNIONED
FROM OPENQUERY(SERVER1,' SELECT
*
FROM yy_T
'
)
union all
SELECT
*
FROM OPENQUERY(SERVER1,' SELECT
*
FROM yk
'
)
DECLARE #dateAsNumber VARCHAR(8);
SET #dateAsNumber = CONVERT(CHAR(6),GETDATE(), 112);
DECLARE #DateConvertedFromNumber DATETIME;
SELECT #DateConvertedFromNumber = CONVERT (DATETIME, CONVERT(CHAR(8), #dateAsNumber + '01'))
select
*
LEFT(CONVERT(VARCHAR, DATEADD(MONTH, -1,#DateConvertedFromNumber), 112),6) AS 'Period'
INTO #temp
from #Unioned
drop table OpenQTable
--if equal to month + 99 = previous month then union 11 tables with last months snapshot
--else
--union 11 tables with 12th table
SET #OpenQuerySql = 'IF (' + cast(#FirstTableMonth as varchar) + '+99) = CONVERT(nvarchar(6), dateadd(month,-1,GETDATE()), 112)
BEGIN
SELECT *
FROM OPENQUERY(['+ #LinkedServerName +'], '''+ #DynamicSQL + ''' )
UNION ALL
SELECT *
FROM #temp
END
else
begin
SELECT *
FROM OPENQUERY(['+ #LinkedServerName +'], '''+ #DynamicSQL + ''' )
UNION ALL
SELECT *
FROM OPENQUERY(['+ #LinkedServerName +'], '''+ #DynamicSQL2 + ''' )
end
'
END
insert into OpenQTable
EXECUTE sp_executesql #OpenQuerySql
go
}

Dynamic SQL for CASE Statements to remove hardcode

I've a Dynamic SQL that is required to be optimized. I need to make CASE Expression Dynamic. I've a list of ATTRIBUTE_LIST & SCENARIO_LIST, that are provided below. I wrote a Function to get them Dynamically. How can I replace Three CASE Expression and make it Dynamic? I'm trying to avoid hard coding.
SET #ATTRIBUTE_LIST = 'symbol_type, currency, performing_status' -- INPUTS
SET #SCENARIO_LIST = 'historicalsimulation_1day_end_10dec2013, historicalsimulation_1day_end_11dec2013'
SELECT CASE
WHEN (GROUPING(Scenario_Name) = 1) THEN ''ALL''
WHEN (Scenario_Name = ''[BaseCase]'') THEN ''BaseCase''
ELSE ISNULL(Scenario_Name, '''')
END AS Scenario_Name,
CASE
WHEN (GROUPING(Symbol_Type) = 1) THEN ''ALL''
ELSE ISNULL(Symbol_Type, '''')
END AS Symbol_Type,
CASE
WHEN (GROUPING(Currency) = 1) THEN ''ALL''
ELSE ISNULL(Currency, '''')
END AS Currency,
CASE
WHEN (GROUPING(Performing_Status) = 1) THEN ''ALL''
ELSE ISNULL(Performing_Status, '''') \
END AS Performing_Status,
SUM(Value) AS ScenarioValue
FROM [20151005_171003_UserName_NT-22_Analysis_Tue] o
LEFT JOIN [20151005_171003_UserName_NT-22_Analysis_Tue_Position_Data] pld
ON o.Position_Unique_Identifier=pld.Position_Unique_Identifier
GROUP BY ' + #ATTRIBUTE_LIST + ' WITH CUBE) AS DATA
PIVOT ( Sum(scenariovalue)
FOR scenario_name IN (' + #SCENARIO_LIST + ')'
It appears you are using SQL Server. Here's a brute-force way of looping over your attributes and building a series of case expressions:
declare #cases nvarchar(max) = '';
declare #l varchar(max) = #ATTRIBUTE_LIST + ',';
declare #ofs int = 0;
declare #pos int = charindex(',', #l, #ofs + 1);
while #pos > 0
begin
if #cases <> '' set #cases = #cases + ',';
set #cases = #cases +
replace('
CASE WHEN (GROUPING(<COL>) = 1) THEN ''ALL''
ELSE ISNULL(<COL>, '''')
END AS <COL>',
'<COL>', substring(#l, #ofs + 1, #pos - #ofs - 1)
);
set #ofs = #pos;
set #pos = charindex(',', #l, #ofs + 1);
end
select #cases;

Passing parametrs to dynamic query

I have a stored procedure as following, I need to pass paramters to the dynamic pivot. My query runs, I just need to do some filtering based on the passed parameters
-- AND (#SelectedSystemIDs IS NULL OR System.ID IN(select * from dbo.SplitInts_RBAR_1(#SelectedSystemIDs, ',')))
--AND ((#PlatformID IS NULL) OR (System.PlatformID = #PlatformID) OR (#PlatformID = 12 AND System.PlatformID <= 2))
-- AND (ServiceEntry.ServiceDateTime between #StartDate and #EndDate)
so I want to add the above criteria, how could achieve that?
ALTER PROCEDURE [dbo].[spExportStuff]
(#StartDate datetime,
#EndDate datetime,
#SelectedSystemIDs nvarchar (2000) = NULL,
#SelectedTsbIDs nvarchar (2000) = NULL,
#UserRoleID int
)
AS
DECLARE #InstrumentType int = NULL
DECLARE #PlatformID int = null
IF (#SelectedSystemIDs = '')
begin
SET #SelectedSystemIDs = NULL
END
IF (#SelectedTsbIDs = '')
begin
SET #SelectedTsbIDs = NULL
END
IF(#UserRoleID = 1)
BEGIN
SET #PlatformID = 1
END
IF(#UserRoleID = 2)
BEGIN
SET #PlatformID = 2
END
IF (#UserRoleID = 3)
BEGIN
SET #PlatformID = 12
END
IF(#UserRoleID = 4)
BEGIN
SET #PlatformID = 3
END
IF(#UserRoleID = 5)
BEGIN
SET #PlatformID = 4
END
IF(#UserRoleID = 6)
BEGIN
SET #PlatformID = NULL
END
DECLARE #PivotColumnHeaders NVARCHAR(MAX)
SELECT #PivotColumnHeaders =
COALESCE(
#PivotColumnHeaders + ',[' + cast(SystemFullName as Nvarchar) + ']',
'[' + cast(SystemFullName as varchar)+ ']'
)
FROM System
DECLARE #PivotTableSQL NVARCHAR(MAX)
SET #PivotTableSQL = N'
SELECT *
FROM (
SELECT
TSBNumber [TSBNumber],
SystemFullName,
ClosedDate
FROM ServiceEntry
INNER JOIN System
ON ServiceEntry.SystemID = System.ID
Group By TSBNumber, SystemFullName, ClosedDate
) AS PivotData
PIVOT (
max(ClosedDate)
FOR SystemFullName IN (
' + #PivotColumnHeaders + '
)
) AS PivotTable
'
EXECUTE(#PivotTableSQL)
you can construct the required criteria as another input to the stored procedure and append it to the dynamic query
ALTER PROCEDURE [dbo].[spExportStuff]
(#StartDate datetime,
#EndDate datetime,
#SelectedSystemIDs nvarchar (2000) = NULL,
#SelectedTsbIDs nvarchar (2000) = NULL,
#UserRoleID int,
#WhereClause varchar(max) -> this is the new parameter.
)
DECLARE #PivotTableSQL NVARCHAR(MAX)
SET #PivotTableSQL = N'
SELECT *
FROM (
SELECT
TSBNumber [TSBNumber],
SystemFullName,
ClosedDate
FROM ServiceEntry
INNER JOIN System
ON ServiceEntry.SystemID = System.ID
Group By TSBNumber, SystemFullName, ClosedDate
) AS PivotData
PIVOT (
max(ClosedDate)
FOR SystemFullName IN (
' + #PivotColumnHeaders + '
)
) AS PivotTable
' + #WhereClause -> you can append the where clause here.
EXECUTE(#PivotTableSQL)

SQL Server concatenation varchar and int

I have two variables:
One is varchar and one is int, I am not sure how to write a while loop using casting so that it will show the following: for example if the while loop is 5 then the result should be
Meter 1
Meter 2
Meter 3
Meter 4
Meter 5.
I have this code, but it is not running (cannot convert varchar to int) even when i do the casting it does not work.
DECLARE #Name varchar (20) = 'Meter',
#MeterNumber int = 1
WHILE (#MeterNumber < 5)
BEGIN
PRINT #Name + ' ' + #MeterNumber
SET #MeterNumber = #MeterNumber + 1
END
This should do the trick: cast the MeterNumber to a varchar when you print it.
DECLARE #Name varchar (20) = 'Meter',
#MeterNumber int = 1
WHILE (#MeterNumber <= 5)
BEGIN
PRINT #Name + ' ' + cast(#MeterNumber as varchar(20))
SET #MeterNumber = #MeterNumber + 1
END
EDIT:
For example I want to declare a third variable that would store each
iteration. Meter 1, Meter 2... but I am not sure where to place it!
DECLARE #Name varchar (20) = 'Meter',
#MeterNumber int = 1 ,
#OutPut varchar(max) =''; -- this can get biiiig.
WHILE (#MeterNumber <= 5)
BEGIN
SET #Output = #Output + #Name + ' ' + cast(#MeterNumber as varchar(20)) + ','
PRINT LEFT(#Output, len(#Output) - 1)
SET #MeterNumber = #MeterNumber + 1
END
Try this one (without LOOP) -
DECLARE
#Name VARCHAR(20) = 'Meter'
, #MeterNumber INT = 5
, #OutPut VARCHAR(MAX) = ''
SELECT #OutPut = STUFF((
SELECT CHAR(13) + #Name + ' ' + CAST(sv.number AS VARCHAR(5))
FROM [master].dbo.spt_values sv
WHERE sv.[type] = 'p'
AND sv.number BETWEEN 1 AND #MeterNumber
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '')
PRINT #OutPut