How to get parent Id from a run time generated row_number() as unique id in SQL - sql-server-2012
I have removed while loop used before but furnishing exact results. Now everything works fine except parentkey.
How to get "parentkey" in the stored procedure perfectly??
The procedure furnishes wrong results if more than 1 same parent is addded in same/different level of bom. The results shows one parent for all childs. It should show both parents separately with childs. The following part does not furnish exact result in case explained above.
(SELECT MAX(e.idcolumn) FROM #tExplode E WHERE e.fcomponent = b.fparent AND e.fcomprev = b.fparentrev AND e.cfacilityid = b.pfacilityid AND e.idcolumn > 0 ) As parentkey
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'M2M_Std_BOM_Explosion' AND type = 'P')
DROP PROCEDURE M2M_Std_BOM_Explosion
GO
CREATE Procedure [dbo].[M2M_Std_BOM_Explosion]
#pcPartNo CHAR(25),
#pcPartRev CHAR(3),
#pcFac CHAR(20),
#plIndent Bit
As
Begin
set nocount on
if object_id('tempdb..#tExplode') is not null drop table #tExplode
declare #sql as varchar(max) = ''
create table #tExplode
(
ID int not null,
lvl int not null,
CompPath varchar(8000),
ItmPath varchar(8000),
display varchar(100),
fcomponent varchar(25),
cfacilityid varchar(20),
fcomprev varchar(3),
fparent varchar(25),
fparentrev varchar(3),
pfacilityid varchar(20),
fitem varchar(6),
fqty numeric(15,5),
fsumqty numeric(15,5),
fst_ef_dt datetime,
fend_ef_dt datetime,
bomid int,
fnoperno int,
fltooling bit,
fbommemo varchar(8000),
fprodcl varchar(20),
flfssvc bit,
idcolumn Integer,
timestamp_column timestamp,
flextend bit,
fcompudrev varchar(3),
fcparudrev varchar(3),
forder int
)
Insert into #tExplode( ID,lvl,CompPath,ItmPath,display,fcomponent,cfacilityid,fcomprev,
fparent,fparentrev,pfacilityid,fitem,fqty,fsumqty,fst_ef_dt,
fend_ef_dt,bomid,fnoperno,fltooling,fbommemo,flfssvc,flextend,
fcompudrev,fcparudrev,forder,idcolumn)
SELECT 1,
0,
Cast(Rtrim(ltrim(#pcFac))+rtrim(ltrim(#pcPartNo))+rtrim(ltrim(#pcPartRev)) as varchar(8000)),
Cast(rtrim(ltrim(#pcFac))+rtrim(ltrim(#pcPartNo))+rtrim(ltrim(#pcPartRev)) as Varchar(8000)),
cast(1 AS varchar(100)),
#pcPartNo,
#pcFac,
#pcPartRev,
'',
'',
'',
'',
1,
1,
{d '1900-01-01'},
{d '1900-01-01'},
0,
'',
0,
'',
0,
0,
'',
'',
0,
0
FROM (SELECT #pcFac fac,
#pcPartNo fpartno,
#pcPartRev frev) x
LEFT JOIN inrtgc i On i.fac=x.fac And i.fpartno=x.fpartno And i.fcpartrev=x.frev
; WITH t AS (
select ID,lvl,CompPath,ItmPath,display,fcomponent,cfacilityid,fcomprev,
fparent,fparentrev,pfacilityid,fitem,fqty,fsumqty,fst_ef_dt,
fend_ef_dt,
bomid,
fnoperno,
fltooling,
fbommemo,
flfssvc,
flextend,
fcompudrev,
fcparudrev,
forder
from #tExplode
UNION ALL
SELECT b.identity_column,
t.lvl+1,
rtrim(ltrim(t.CompPath)) + '!' + rtrim(ltrim(b.pfacilityid)) + rtrim(ltrim(b.fcomponent)) + Replicate(' ',25-Len(rtrim(ltrim(b.fcomponent))))+ rtrim(ltrim(b.fcomprev + '!')),
rtrim(ltrim(t.ItmPath)) + '!' + rtrim(ltrim(b.fitem)),
Cast(replicate(' ',2*t.lvl) + b.fcomponent as Varchar(100)),
Cast(b.fcomponent as Varchar(25)),
Cast(b.cfacilityid as Varchar(20)),
Cast(b.fcomprev as Varchar(3)),
Cast(b.fparent as Varchar(25)),
Cast(b.fparentrev as Varchar(3)),
Cast(b.pfacilityid as Varchar(20)),
Cast(b.fitem as varchar(6)),
b.fqty,
Cast(CASE
WHEN b.flextend = 1 THEN b.fqty * ISNULL(t.fsumqty, cast(1 AS numeric(15,5)))
ELSE b.fqty
END as Numeric(15,5)),
b.fst_ef_dt,
b.fend_ef_dt,
b.identity_column,
ISNULL(b.fnoperno,cast(0 AS int)),
b.fltooling,
Cast(b.fbommemo as Varchar(8000)),
b.flfssvc,
b.flextend,
Cast(b.fcompudrev as Varchar(3)),
Cast(b.fcparudrev as Varchar(3)),
0
FROM inboms b
inner join t ON b.pFacilityID = t.cFacilityID
AND b.fparent = t.fcomponent
AND b.fparentrev = t.fcomprev
)
insert into #tExplode
(ID,lvl,CompPath,ItmPath,display,fcomponent,cfacilityid,fcomprev,
fparent,fparentrev,pfacilityid,fitem,fqty,fsumqty,fst_ef_dt,
fend_ef_dt,
bomid,
fnoperno,
fltooling,fbommemo,flfssvc,
flextend,
fcompudrev,fcparudrev,forder,idcolumn)
select ID,lvl,CompPath,ItmPath,display,fcomponent,cfacilityid,fcomprev,
fparent,fparentrev,pfacilityid,fitem,fqty,fsumqty,fst_ef_dt,
fend_ef_dt,
bomid,
fnoperno,
fltooling,fbommemo,
flfssvc,
flextend,
fcompudrev,fcparudrev,forder,row_number() over (order by lvl,comppath,cfacilityid,fcomponent,fcomprev,forder) from t
Set #sql = 'select b.idcolumn,b.lvl,
b.comppath,
b.itmpath,
b.display,
CASE WHEN m.fluseudrev = 1 THEN b.fcompudrev ELSE b.fcomprev END as disprev,
b.fitem,
fsource,
b.fqty,
CASE when b.flextend = 1 then b.fsumqty ELSE ((b.fqty * ISNULL(b.fsumqty, cast(1 AS numeric(15,5))))/Isnull(i.fSpq,1)) END as fsumqty,
fmeasure,
b.fnoperno,
CASE WHEN inbomm.fpartno IS NULL THEN SPACE(1) ELSE ''*'' END as isparent, --Working
b.fst_ef_dt,
b.fend_ef_dt,
b.bomid,
b.fcomponent,
b.cfacilityid,
b.fcomprev,
m.fdescript as fdesc,
b.fparent,
b.fparentrev,
b.pfacilityid,
ISNULL(m.identity_column, CAST(0 As Int)) as partid,
fidims,
Case When m.fcstscode=''O'' Then ''Obsolete''
Else
CASE WHEN NOT ((b.fst_ef_dt IS NULL) OR (b.fst_ef_dt={d ''1900-01-01''})) AND
DATEDIFF(day,b.fst_ef_dt, GetDate()) < 0
THEN ''Future''
WHEN NOT ((b.fend_ef_dt IS NULL) OR (b.fend_ef_dt={d ''1900-01-01''})) AND
DATEDIFF(day,b.fEnd_ef_dt, GETDATE()) > 0
THEN ''Expired''
ELSE ''Current''
END
End as effectivity,
b.fltooling,
b.fbommemo,
m.fprodcl,
fllotreqd,
b.flfssvc,
b.timestamp_column,
(SELECT MAX(e.idcolumn) FROM #tExplode E WHERE e.fcomponent = b.fparent AND e.fcomprev = b.fparentrev AND e.cfacilityid = b.pfacilityid AND e.idcolumn > 0 ) As parentkey,
b.flextend,
m.fluseudrev,
b.fcompudrev,
b.fcparudrev,
b.forder
from #tExplode b LEFT OUTER JOIN inmastx m ON
b.cFacilityID = m.fac AND
b.fcomponent = m.fpartno AND
b.fcomprev = m.frev
LEFT OUTER JOIN inbomm ON
b.pfacilityid = inbomm.facilityid AND
b.fComponent = InBomm.fPartno AND
b.fCompRev = InBomm.fcPartRev
LEFT OUTER JOIN inrtgc i ON
b.pfacilityid = i.fac AND
b.fComponent = i.fPartno AND
b.fCompRev = i.fcPartRev
where ' + case when #plIndent= 1 then 'b.lvl >= 1' else 'b.lvl = 1' end + '
order by ' + case when #plIndent= 1 then 'b.comppath,b.cfacilityid,b.fcomponent,b.fcomprev,b.forder' else 'b.comppath,b.forder' end + ''
Exec(#sql)
drop table #tExplode
end
--How to get "parentkey" in the stored procedure perfectly??
--The procedure furnishes wrong results if more than 1 same parent is addded in --same/different level of bom. The results shows one parent for all childs.
Related
How to replace where clause with a function and use it in stored procedures?
I have two stored procedures that they have the same where clause, one of them is use for pagination: ALTER PROCEDURE [dbo].[ret_PayrollCalculations_GetPagedFilteredPersonnels] ( #SortField varchar(512), #PageNo int, #PageSize int, #CalculationCommandType int, #StartWorkingPeriodId int, #StartYear int, #EndWorkingPeriodId int, #EndYear int, #Status int, #SalariedGuid uniqueidentifier, #SalariedType int, #OfficeNumber varchar(64), #SalariedResultSetId int, #Keyword nvarchar(2024), #OperationalUnitIds [dbo].[ListOfID] READONLY ) AS DECLARE #AccessibleSalariedGuids [dbo].[ListOfGuid] IF EXISTS (SELECT * FROM #OperationalUnitIDs) BEGIN INSERT INTO #AccessibleSalariedGuids SELECT FeatureGuid FROM prs_OperationalUnitFeatures WHERE OperationalUnitID in (SELECT * FROM #OperationalUnitIDs) AND FeatureFlag IN (2,4) END ELSE BEGIN INSERT INTO #AccessibleSalariedGuids SELECT [Guid] FROM ret_vwSalaried END DECLARE #OffsetRows INT = CASE WHEN #PageNo = 1 THEN 0 ELSE (#PageNo - 1) * #PageSize END; DECLARE #TotalCount INT; WITH Result AS( SELECT CASE WHEN #SortField = N'[FullName]' THEN ROW_NUMBER() OVER (ORDER BY salaried.[FullName]) WHEN #SortField = N'[FullName] DESC' THEN ROW_NUMBER() OVER (ORDER BY salaried.[FullName] DESC) WHEN #SortField = N'[WorkingPeriodTitle]' THEN ROW_NUMBER() OVER (ORDER BY calcs.[Year],workingPeriods.[Index]) WHEN #SortField = N'[WorkingPeriodTitle] DESC' THEN ROW_NUMBER() OVER (ORDER BY calcs.[Year] DESC,workingPeriods.[Index] DESC) WHEN #SortField = N'[PersonnelNo]' THEN ROW_NUMBER() OVER (ORDER BY salaried.[PersonnelNo]) WHEN #SortField = N'[PersonnelNo] DESC' THEN ROW_NUMBER() OVER (ORDER BY salaried.[PersonnelNo] DESC) END AS [RowNumber], calcs.[Guid], calcs.[CalculationCommandGuid], calcs.[SalariedGuid], salaried.[PersonnelNo], salaried.[FullName] AS [PersonnelFullName], command.[Type] [CommandType], salaried.[SalariedType], workingPeriods.Title AS [WorkingPeriodTitle], command.[MainYear] AS [Year], command.[Approved], command.[FinalApproved] FROM ret_PayrollCalculationCommands command INNER JOIN ret_PayrollCalculations calcs ON calcs.[CalculationCommandGuid] = command.[Guid] INNER JOIN ret_vwSalaried salaried ON calcs.[SalariedGuid] = salaried.[Guid] INNER JOIN prs_workingPeriods workingPeriods ON workingPeriods.[Id] = command.[MainWorkingPeriodID] WHERE ISNULL(calcs.[MainCalculation],0) = 1 AND ISNULL(command.[Deleted],0)=0 AND (#Keyword = '' OR salaried.PersonnelNo = #Keyword OR salaried.FullName LIKE N'%' + #Keyword + '%' OR salaried.FullNameReversed LIKE N'%' + #Keyword + '%') AND (ISNULL(#calculationCommandType, 0) = 0 OR command.[Type] = #calculationCommandType) AND (ISNULL(#StartYear, 0) = 0 OR command.[MainYear] >= #StartYear) AND (ISNULL(#StartWorkingPeriodId, 0) = 0 OR command.[MainWorkingPeriodID] >= #StartWorkingPeriodId) AND (ISNULL(#EndYear, 0) = 0 OR command.[MainYear] <= #EndYear) AND (ISNULL(#EndWorkingPeriodId, 0) = 0 OR command.[MainWorkingPeriodID] <= #EndWorkingPeriodId) AND (ISNULL(#Status, -1) = -1 OR command.[Approved] = #Status) AND (ISNULL(#SalariedType, -1) = -1 OR salaried.[SalariedType] = #SalariedType) AND (ISNULL(#SalariedGuid,'00000000-0000-0000-0000-000000000000') = '00000000-0000-0000-0000-000000000000' OR calcs.[SalariedGuid] = #SalariedGuid) AND (#OfficeNumber IS NULL OR salaried.[OfficeNumber] LIKE '%'+#OfficeNumber+'%') AND (ISNULL(#SalariedResultSetId, -1) = -1 OR calcs.[SalariedGuid] IN (SELECT [SalariedGuid] FROM ret_SalariedResultSetItems WHERE SalariedResultSetID = #SalariedResultSetId)) AND (calcs.[SalariedGuid] IN (SELECT * FROM #AccessibleSalariedGuids)) ), TableForTotalCount AS (SELECT COUNT(*) As TotalCount FROM Result) SELECT (SELECT TOP 1 TotalCount FROM TableForTotalCount) AS TotalCount, * FROM Result ORDER BY [RowNumber] OFFSET #OffsetRows ROWS FETCH NEXT #PageSize ROWS ONLY and another one supposed to return some Guids ALTER PROCEDURE [dbo].[ret_PayrollCalculations_GetFilteredPersonnels] ( #CalculationCommandType int, #StartWorkingPeriodId int, #StartYear int, #EndWorkingPeriodId int, #EndYear int, #Status int, #SalariedGuid uniqueidentifier, #SalariedType int, #OfficeNumber varchar(64), #SalariedResultSetId int, #Keyword nvarchar(2024), #OperationalUnitIds [dbo].[ListOfID] READONLY ) AS DECLARE #AccessibleSalariedGuids [dbo].[ListOfGuid] IF EXISTS (SELECT * FROM #OperationalUnitIDs) BEGIN INSERT INTO #AccessibleSalariedGuids SELECT FeatureGuid FROM prs_OperationalUnitFeatures WHERE OperationalUnitID in (SELECT * FROM #OperationalUnitIDs) AND FeatureFlag IN (2,4) END ELSE BEGIN INSERT INTO #AccessibleSalariedGuids SELECT [Guid] FROM ret_vwSalaried END SELECT calcs.[Guid] FROM ret_PayrollCalculationCommands command INNER JOIN ret_PayrollCalculations calcs ON calcs.[CalculationCommandGuid] = command.[Guid] INNER JOIN ret_vwSalaried salaried ON calcs.[SalariedGuid] = salaried.[Guid] WHERE ISNULL(calcs.[MainCalculation],0) = 1 AND ISNULL(command.[Deleted],0)=0 AND (#Keyword = '' OR salaried.PersonnelNo = #Keyword OR salaried.FullName LIKE N'%' + #Keyword + '%' OR salaried.FullNameReversed LIKE N'%' + #Keyword + '%') AND (ISNULL(#calculationCommandType, 0) = 0 OR command.[Type] = #calculationCommandType) AND (ISNULL(#StartYear, 0) = 0 OR command.[MainYear] >= #StartYear) AND (ISNULL(#StartWorkingPeriodId, 0) = 0 OR command.[MainWorkingPeriodID] >= #StartWorkingPeriodId) AND (ISNULL(#EndYear, 0) = 0 OR command.[MainYear] <= #EndYear) AND (ISNULL(#EndWorkingPeriodId, 0) = 0 OR command.[MainWorkingPeriodID] <= #EndWorkingPeriodId) AND (ISNULL(#Status, -1) = -1 OR command.[Approved] = #Status) AND (ISNULL(#SalariedType, -1) = -1 OR salaried.[SalariedType] = #SalariedType) AND (ISNULL(#SalariedGuid,'00000000-0000-0000-0000-000000000000') = '00000000-0000-0000-0000-000000000000' OR calcs.[SalariedGuid] = #SalariedGuid) AND (#OfficeNumber IS NULL OR salaried.[OfficeNumber] LIKE '%'+#OfficeNumber+'%') AND (ISNULL(#SalariedResultSetId, -1) = -1 OR calcs.[SalariedGuid] IN (SELECT [SalariedGuid] FROM ret_SalariedResultSetItems WHERE SalariedResultSetID = #SalariedResultSetId)) AND (calcs.[SalariedGuid] IN (SELECT * FROM #AccessibleSalariedGuids)) When a bug appears I have to fix the problem in both stored procedures, to avoid duplication I wanted Where clauses in a function and call the function in stored procedures, But I don't know how?
This is how I would approach this: If you're using Microsoft sql-server, you can make transact-sql code. Convert your sql procedure into a string and make the Where clause a text variable that you declare elsewhere. So it's creating a meta- procedure. For eg. DECLARE #whereClause LONGTEXT; DECLARE #SQLString LONGTEXT; SET #whereClause = 'i=1' SET #SQLString = 'SELECT * FROM table WHERE' & #whereClause sp_executesql SQLString
MSSQL - Create table function, return substring
I need to create this table function. The function needs to return single words from passed parameters like: hello, hhuu, value The table function should return: hello, hhuu, value But I am always getting some errors, please could you help me?
you can write as: DECLARE #input_char VARCHAR(255) SET #input_char = 'hello, hhuu, value' ;WITH cte AS ( SELECT CAST('<r>' + REPLACE(#input_char, ' ', '</r><r>') + '</r>' AS XML) AS input_char ) SELECT rtrim( LTRIM (xTable.xColumn.value('.', 'VARCHAR(MAX)')) ) AS input_char FROM cte CROSS APPLY input_char.nodes('//r') AS xTable(xColumn)
Please give a look at this article: http://www.codeproject.com/Tips/625872/Convert-a-CSV-delimited-string-to-table-column-in and you could use ' ' (space) as delimiter. SELECT * FROM dbo.CSVtoTable('hello, hhuu, value', ' ')
I have used the following function many times. It is a bit lengthy forgive me, but it has become a great tool for me. CREATE Function [dbo].[ParseText2Table] ( #p_SourceText varchar(MAX) ,#p_Delimeter varchar(100) = ',' --default to comma delimited. ) RETURNS #retTable TABLE ( POSITION INT ,Int_Value bigint ,Num_value REAL--Numeric(18,3) ,txt_value varchar(MAX) ) AS BEGIN DECLARE #tmpTable TABLE ( Position2 INT IDENTITY(1,1) PRIMARY KEY ,Int_Value bigint ,Num_value REAL--Numeric(18,3) ,txt_value varchar(MAX) ) DECLARE #w_Continue INT ,#w_StartPos INT ,#w_Length INT ,#w_Delimeter_pos INT ,#w_tmp_int bigint ,#w_tmp_num REAL--numeric(18,3) ,#w_tmp_txt varchar(MAX) ,#w_Delimeter_Len INT IF len(#p_SourceText) = 0 BEGIN SET #w_Continue = 0 -- force early exit END ELSE BEGIN -- if delimiter is ' ' change IF #p_Delimeter = ' ' BEGIN SET #p_SourceText = replace(#p_SourceText,' ','ÿ') SET #p_Delimeter = 'ÿ' END -- parse the original #p_SourceText array into a temp table SET #w_Continue = 1 SET #w_StartPos = 1 SET #p_SourceText = RTRIM( LTRIM( #p_SourceText)) SET #w_Length = DATALENGTH( RTRIM( LTRIM( #p_SourceText))) SET #w_Delimeter_Len = len(#p_Delimeter) END WHILE #w_Continue = 1 BEGIN SET #w_Delimeter_pos = CHARINDEX( #p_Delimeter ,(SUBSTRING( #p_SourceText, #w_StartPos ,((#w_Length - #w_StartPos) + #w_Delimeter_Len))) ) IF #w_Delimeter_pos > 0 -- delimeter(s) found, get the value BEGIN SET #w_tmp_txt = LTRIM(RTRIM( SUBSTRING( #p_SourceText, #w_StartPos ,(#w_Delimeter_pos - 1)) )) IF dbo.isReallyNumeric(#w_tmp_txt) = 1 --and not #w_tmp_txt in('.', '-', '+', '^') BEGIN --set #w_tmp_int = cast( cast(#w_tmp_txt as real) as bigint)--numeric) as bigint) SET #w_tmp_int = CASE WHEN (CAST(#w_tmp_txt AS REAL) BETWEEN -9223372036854775808 AND 9223372036854775808) THEN CAST( CAST(#w_tmp_txt AS REAL) AS bigint) ELSE NULL END SET #w_tmp_num = CAST( #w_tmp_txt AS REAL)--numeric(18,3)) END ELSE BEGIN SET #w_tmp_int = NULL SET #w_tmp_num = NULL END SET #w_StartPos = #w_Delimeter_pos + #w_StartPos + (#w_Delimeter_Len- 1) END ELSE -- No more delimeters, get last value BEGIN SET #w_tmp_txt = LTRIM(RTRIM( SUBSTRING( #p_SourceText, #w_StartPos ,((#w_Length - #w_StartPos) + #w_Delimeter_Len)) )) IF dbo.isReallyNumeric(#w_tmp_txt) = 1 --and not #w_tmp_txt in('.', '-', '+', '^') BEGIN --set #w_tmp_int = cast( cast(#w_tmp_txt as real) as bigint)--as numeric) as bigint) SET #w_tmp_int = CASE WHEN (CAST(#w_tmp_txt AS REAL) BETWEEN -9223372036854775808 AND 9223372036854775808) THEN CAST( CAST(#w_tmp_txt AS REAL) AS bigint) ELSE NULL end SET #w_tmp_num = CAST( #w_tmp_txt AS REAL)--numeric(18,3)) END ELSE BEGIN SET #w_tmp_int = NULL SET #w_tmp_num = NULL END SELECT #w_Continue = 0 END INSERT INTO #tmpTable VALUES( #w_tmp_int, #w_tmp_num, #w_tmp_txt ) END INSERT INTO #retTable SELECT Position2, Int_Value ,Num_value ,txt_value FROM #tmpTable RETURN END Here are the supporting functions for above as well: CREATE FUNCTION dbo.isReallyInteger ( #num VARCHAR(64) ) RETURNS BIT BEGIN IF LEFT(#num, 1) = '-' SET #num = SUBSTRING(#num, 2, LEN(#num)) RETURN CASE WHEN PATINDEX('%[^0-9-]%', #num) = 0 AND CHARINDEX('-', #num) <= 1 AND #num NOT IN ('.', '-', '+', '^') AND LEN(#num)>0 AND #num NOT LIKE '%-%' THEN 1 ELSE 0 END END CREATE FUNCTION dbo.isReallyNumeric ( #num VARCHAR(64) ) RETURNS BIT BEGIN IF LEFT(#num, 1) = '-' SET #num = SUBSTRING(#num, 2, LEN(#num)) DECLARE #pos TINYINT SET #pos = 1 + LEN(#num) - CHARINDEX('.', REVERSE(#num)) RETURN CASE WHEN PATINDEX('%[^0-9.-]%', #num) = 0 AND #num NOT IN ('.', '-', '+', '^') AND LEN(#num)>0 AND #num NOT LIKE '%-%' AND ( ((#pos = LEN(#num)+1) OR #pos = CHARINDEX('.', #num)) ) THEN 1 ELSE 0 END END Usage Examples: --Single Character Delimiter --select * from dbo.ParseText2Table('100|120|130.56|Yes|Cobalt|Blue','|') --select txt_value from dbo.ParseText2Table('100 120 130.56 Yes Cobalt Blue',' ') where Position = 3 --select * from dbo.ParseText2Table('100,120,130.56,Yes,Cobalt,Blue,,',',') /* POSITION Int_Value Num_value txt_value ----------- ----------- -------------------- -------------- 1 100 100.000 100 2 120 120.000 120 3 131 130.560 130.56 4 NULL NULL Yes 5 NULL NULL Cobalt Blue */
Have someone a function for SQL Server that given a pattern and a value could return a normalized value
I'm programming a function in SQL 2008R2 that i could give it some parameters like a value varchar, a pattern varchar, a separator char and a filler also char. Then I would like to give the value '22687' with the patter '000.000.000.000', a separator '.' and the filler would be '0', then i would like to expect the function will return '000.000.022.687', does any one have a function already done that can do this? Something like this: DECLARE #valor VARCHAR(30) DECLARE #formato VARCHAR(30) DECLARE #separador CHAR(1) DECLARE #rellenarcon CHAR(1) SELECT #valor = '22959' SELECT #formato = '000.000.000.000' SELECT #separador = '.' SELECT #rellenarcon = '0' DECLARE #n INTEGER DECLARE #m INTEGER DECLARE #i INTEGER DECLARE #j INTEGER SELECT #n = LEN(#formato) SELECT #m = LEN(#valor) SELECT #i = 1 SELECT #j = 1 DECLARE #res2 varchar(30) SELECT #res2 = '' SELECT #valor = REVERSE(#valor) WHILE #i<=#n BEGIN if SUBSTRING(#formato,#i,1) <> #separador begin IF #j<=#m BEGIN SELECT #res2 = #res2 + SUBSTRING(#valor,#j,1) SELECT #i=#i+1 SELECT #j=#j+1 END ELSE BEGIN SELECT #res2 = #res2 + #rellenarcon SELECT #i=#i+1 END end else BEGIN SELECT #res2 = #res2 + #separador SELECT #i=#i+1 END END print reverse(#res2) Is a crossover code from java to tsql, the original code in java is: public static String formatear(String valor, String formato, char separator, char fillWith, Map<Integer, String> params) { int n = formato.length() - 1; int m = valor.length() - 1; int i = n; int j = m; StringBuilder res = new StringBuilder(formato); for(; i >= 0; i--) { if(res.charAt(i) != separator) { if(j >= 0) { res.deleteCharAt(i); res.insert(i, valor.charAt(j--)); } else { res.deleteCharAt(i); res.insert(i, fillWith); } } } if(params != null) { Set<Integer> keys = params.keySet(); for(Integer key : keys) { i = key; res.deleteCharAt(i); res.insert(i, params.get(key)); } } return res.toString(); }
The following assumes well-formed inputs, e.g. the value is not longer than the pattern. declare #Pattern as VarChar(64) = '000.000.000.000'; declare #Fill as Char = '0'; declare #Value as VarChar(64) = '22687'; declare #False as Bit = 0; declare #True as Bit = 1; with Gargoyle as ( select #Pattern as Pattern, #Value as Value, Cast( '' as VarChar(64) ) as Buffer, case when Right( #Pattern, 1 ) = #Fill then #True else #False end as Fill union all select -- Always consume a character from the pattern. Left( Pattern, Len( Pattern ) - 1 ), -- Consume a character from the value if the pattern contains fill at the current position. case when Fill = #True and Value != '' then Left( Value, Len( Value ) - 1 ) else Value end, -- Add the correct character to the buffer. Cast( case when Fill = #True and Value != '' then Right( Value, 1 ) else Right( Pattern, 1 ) end + Buffer as VarChar(64) ), -- Check the next pattern character for fill. case when Len( Pattern ) = 1 then #False when Substring( Pattern, Len( Pattern ) - 1, 1 ) = #Fill then #True else #False end from Gargoyle where Pattern != '' ) select Buffer from Gargoyle where Pattern = ''; Or, as a function: create function dbo.PatternFill( #Pattern as VarChar(64), #Fill as Char, #Value as VarChar(64) ) returns VarChar(64) as begin declare #Buffer as VarChar(64) = '' declare #PatternChar as Char = Right( #Pattern, 1 ) declare #ValueChar as Char = Right( #Value, 1 ) while #Pattern != '' begin if #PatternChar = #Fill and #ValueChar != '' begin -- Replace a fill character with a value character. select #Buffer = #ValueChar + #Buffer if Len( #Value ) > 1 select #Value = Left( #Value, Len( #Value ) - 1 ), #ValueChar = Right( #Value, 1 ) else select #ValueChar = '', #Value = '' end else begin -- Copy the pattern character. select #Buffer = #PatternChar + #Buffer end if Len( #Pattern ) > 1 select #Pattern = Left( #Pattern, Len( #Pattern ) - 1 ), #PatternChar = Right( #Pattern, 1 ) else select #PatternChar = '', #Pattern = '' end return #Buffer end go declare #Result as VarChar(64) declare #Count as Int = 1000000 declare #Start as DateTime = GetDate() while #Count > 0 select #Result = dbo.PatternFill( '000.000.000.000', '0', '22687' ), #Count = #Count - 1 select #Result as [Result], DateDiff( ms, #Start, GetDate() ) as [Total ms] 1,000,000 iterations on my notebook took 151,656ms, but it's busy BOINCing. That's simple timing with no correction for the time consumed by an empty loop or calling an empty function.
This query will do it: ;with cteZeroPadded(Num) as ( Select Right('000000000000' + '22687', 12) ) ,cteSplit as ( Select SUBSTRING(Num, 1, 3) Col1 ,SUBSTRING(Num, 4, 3) Col2 ,SUBSTRING(Num, 7, 3) Col3 ,SUBSTRING(Num, 10, 3) Col4 From cteZeroPadded ) Select Col1 + '.' + Col2 + '.' + Col3 + '.' + Col4 From cteSplit
In SQLServer2005+ you can use option with recursive CTE DECLARE #valor varchar(30) = '22959', #formato varchar(30) = '000000000000000', #text varchar(30), #result varchar(30) = N'' SET #text = REVERSE(RIGHT(#formato + #valor, 15)) ;WITH cte AS ( SELECT 1 AS Number, SUBSTRING(#text, 1, 1) AS Num UNION ALL SELECT c.Number + 1, CASE WHEN c.Number IN(3, 7, 11) THEN '.' ELSE SUBSTRING(#text, CASE WHEN c.Number > 11 THEN c.Number - 2 WHEN c.Number > 7 THEN c.Number - 1 WHEN c.Number > 3 THEN c.Number ELSE c.Number + 1 END, 1) END FROM cte c WHERE Number < LEN(#text) ) SELECT #result += c.Num FROM cte c ORDER BY Number DESC SELECT #result See demo on SQLFiddle
Improve case statement in order clause
I have the store sql ALTER procedure [dbo].[TNNews_User_SearchBasic] #Title nvarchar(400), #CategoryId int, #IsInterested int, #IsHot int, #IsTopCategory int, #IsPublish int, #PageSize int, #PageIndex int, #OrderBy varchar(20), #PortalId int, #LanguageId varchar(6) as DECLARE #EndTime DATETIME DECLARE #StartTime DATETIME SET #StartTime = GETDATE() declare #tbCategory table(Id int) DECLARE #StartRowIndex INT IF #PageSize=0 SELECT #PageSize=count(*) FROM TNNews IF(#PageIndex<0) SET #PageIndex=0 SET #StartRowIndex = #PageSize*(#PageIndex-1)+1 ;WITH tmpCategory(Id, Name,ParentId,Level) AS ( SELECT e.Id, e.Name, e.ParentId, 1 FROM dbo.TNCategory AS e WHERE Id = #CategoryId or (#CategoryId='' and ParentId<=0) UNION ALL SELECT e.Id, e.Name, e.ParentId, Level + 1 FROM dbo.TNCategory AS e JOIN tmpCategory AS d ON e.ParentId = d.Id ) insert #tbCategory select Id from tmpCategory ;WITH tmpNews as ( SELECT a.Id,a.Title,a.Subject ,ROW_NUMBER() OVER (ORDER BY (Publisheddate) desc) as ThuTuBanGhi FROM dbo.TNNews a where 1 = 1 --and ( Title like '%'+#Title+'%') and (#CategoryId = -1 or exists (select 0 from #tbCategory b where b.Id = a.CategoryId)) and (#IsInterested = -1 or IsIntrested = #IsInterested ) and (#IsHot = -1 or IsHot = #IsHot ) and (#IsTopCategory = -1 or IsTopCategory = #IsTopCategory ) and (#IsPublish = -1 or IsPublished = #IsPublish) and PortalId=#PortalId and LanguageId = #LanguageId ) select *, (select COUNT(Id) from tmpNews) as 'TongSoBanGhi' from tmpNews WHERE ThuTuBanGhi BETWEEN (#StartRowIndex) AND (#StartRowIndex + #PageSize-1) SET #EndTime = GETDATE() PRINT 'StartTime = ' + CONVERT(VARCHAR(30),#StartTime,121) PRINT ' EndTime = ' + CONVERT(VARCHAR(30),#EndTime,121) PRINT ' Duration = ' + STR(DATEDIFF(MILLISECOND,#StartTime,#EndTime)) + ' millisecond' select STR(DATEDIFF(MILLISECOND,#StartTime,#EndTime)) After this store excute EXEC [dbo].[TNNews_User_SearchBasic] #Title='', #CategoryId = '', #IsInterested = -1, #IsHot = -1, #IsTopCategory = -1, #IsPublish = -1, #PageSize = 20, #PageIndex = 1, #OrderBy = '', #PortalId = 0, #LanguageId = N'vi-VN' go The time excute about "200ms". And I create a new store "TNNews_User_SearchBasic1" with some change. ..... --,ROW_NUMBER() OVER (ORDER BY (Publisheddate) desc) as ThuTuBanGhi ,ROW_NUMBER() OVER (ORDER BY (case when #OrderBy='VIEW_COUNT' then ViewCount else PublishedDate end) desc) as ThuTuBanGhi ..... and now the time excute this store EXEC [dbo].[TNNews_User_SearchBasic1] #Title='', #CategoryId = '', #IsInterested = -1, #IsHot = -1, #IsTopCategory = -1, #IsPublish = -1, #PageSize = 20, #PageIndex = 1, #OrderBy = '', #PortalId = 0, #LanguageId = N'vi-VN' GO about 900ms. I don't understand why there is a change. Please help me improve these stores. PS: I put example db at: http://anhquan22.tk/Portals/0/Videos/web.rar
Finished analysis the structure of your database. The part of the problem is hiding in the table structure. I have prepared a backup for you. In it, I slightly modified scheme to improve performance and some normalize the table. You can download it from this link. ...to your question, I would do like this - DECLARE #SQL NVARCHAR(1000) SELECT #SQL = N' ;WITH tmpCategory (Id, Name, ParentId, [Level]) AS ( SELECT e.Id , e.Name , e.ParentId , 1 FROM dbo.TNCategory e WHERE Id = #CategoryId OR (#CategoryId = '''' AND ParentId <= 0) UNION ALL SELECT e.Id , e.Name , e.ParentId , [Level] + 1 FROM dbo.TNCategory e JOIN tmpCategory d ON e.ParentId = d.Id ) SELECT a.Id , ROW_NUMBER() OVER (ORDER BY ' + CASE WHEN #OrderBy = 'VIEW_COUNT' THEN 'ViewCount' ELSE 'PublishedDate' END +' DESC) AS ThuTuBanGhi FROM dbo.TNNewsMain a where PortalId = #PortalId AND LanguageId = #LanguageId' + CASE WHEN #IsInterested != -1 THEN ' AND IsInterested = #IsInterested' ELSE '' END + CASE WHEN #IsHot != -1 THEN ' AND IsHot = #IsHot' ELSE '' END + CASE WHEN #IsTopCategory != -1 THEN ' AND IsTopCategory = #IsTopCategory' ELSE '' END + CASE WHEN #IsPublish != -1 THEN ' AND IsPublish = #IsPublish' ELSE '' END + CASE WHEN #CategoryId != -1 THEN '' ELSE ' AND EXISTS(SELECT 1 FROM tmpCategory b WHERE b.Id = a.CategoryId)' END INSERT INTO #temp (Id, ThuTuBanGhi) EXECUTE sp_executesql #SQL , N'#PortalId INT , #LanguageId VARCHAR(6) , #CategoryId INT , #IsInterested INT , #IsHot INT , #IsTopCategory INT , #IsPublish INT' , #PortalId = #PortalId , #LanguageId = #LanguageId , #CategoryId = #CategoryId , #IsInterested = #IsInterested , #IsHot = #IsHot , #IsTopCategory = #IsTopCategory , #IsPublish = #IsPublish; SELECT d.Id , tm.Title , tm.[Subject] , d.ThuTuBanGhi , c.TongSoBanGhi FROM ( SELECT t.Id , t.ThuTuBanGhi FROM #temp t WHERE t.ThuTuBanGhi BETWEEN #StartRowIndex AND #StartRowIndex + #PageSize - 1 ) d JOIN TNNewsMain tm ON d.Id = tm.Id CROSS JOIN ( SELECT TongSoBanGhi = (SELECT COUNT(1) FROM #temp) ) c
SQL query - selecting the columns whose grand total is greater than 0
Here is my SQL query: DROP TABLE #tempi CREATE TABLE #tempi ( nav1 VARCHAR(50), nav2 INT , nav3 INT , nav4 INT , nav5 INT ) INSERT INTO #tempi SELECT COALESCE(CAST(machinename AS VARCHAR(28)), 'Grand Total:') AS machinename , SUM(CASE WHEN vfrm.job_id = '1001' THEN DATEDIFF(mi, 0, total_time) END) AS crate_small , SUM(CASE WHEN vfrm.job_id = '1002' THEN DATEDIFF(mi, 0, total_time) END) AS crate_medium , SUM(CASE WHEN vfrm.job_id = '1014' THEN DATEDIFF(mi, 0, total_time) END) AS front_air_deflector, SUM(CASE WHEN vfrm.job_id = '9999' THEN DATEDIFF(mi, 0, total_time) END) AS no_schedule FROM ven_fullreportmaster vfrm INNER JOIN ven_descriptionmaster vdm ON vdm.description_id = vfrm..description_id INNER JOIN ven_machinemaster vm ON vm.machine_id = vfrm..machine_id WHERE vfrm.entry_date = CONVERT(VARCHAR, GETDATE()-7, 105) --and vfrm.shift_id =1 AND vfrm.is_task_completed = 'Y' GROUP BY machinename WITH ROLLUP The output in tempi table: nav1 nav2 nav3 nav4 nav5 abc 0:0 0:0 0:0 1:0 def 0:0 1:0 2:0 1:0 ghi 0:0 0:0 0:0 1:0 grand 0:0 1:0 2:0 3:0 total I want to select the columns whose grand total is greater than 0. How to achieve it?
CREATE TABLE #tempi ( nav1 VARCHAR(50), nav2 INT, nav3 INT, nav4 INT, nav5 INT ) INSERT INTO #tempi VALUES('Grand Total:', 0.0, 1.0, 2.0, 3.0) DECLARE #dynsql NVARCHAR(MAX) SELECT #dynsql = ISNULL(#dynsql + ',','') + QUOTENAME(col) FROM #tempi UNPIVOT(nav FOR col IN (nav2,nav3,nav4,nav5)) AS unpvt WHERE nav1 = 'Grand Total:' AND nav>0 IF(##ROWCOUNT > 0) BEGIN SET #dynsql = 'SELECT ' + #dynsql + ' FROM #tempi' EXEC(#dynsql) END DROP TABLE #tempi Or if you can't use UNPIVOT... DECLARE #dynsql NVARCHAR(MAX) SELECT #dynsql = CASE WHEN nav2>0 THEN ',nav2' ELSE '' END + CASE WHEN nav3>0 THEN ',nav3' ELSE '' END + CASE WHEN nav4>0 THEN ',nav4' ELSE '' END + CASE WHEN nav5>0 THEN ',nav5' ELSE '' END FROM #tempi WHERE nav1 = 'Grand Total:' IF(LEN(#dynsql) > 0) BEGIN SET #dynsql = STUFF(#dynsql,1,1,'SELECT ') + ' FROM #tempi' EXEC(#dynsql) END