Extract and Separate Numeric - sql-server

I have a table below.
Client Name
-----------------------
Mukherjee_ 2697231 Gehrmann _ 298053524
Butt Glen_740708968 Amanda_259055000
Quirk Michael_ 65941412 and Leanne _817498908
Butt Glen_740708968 Amanda_259055000 Tristan 3939393939
Kryger Aaron _ 606506375
Krebs Paul
Haddrill Clare _ 333900499 McRedmond Patrick _557887778
I need to extract the numbers only and the numbers must be separated.
Numeric
----------------
2697231 298053524
740708968 259055000
65941412 817498908
740708968 259055000 3939393939
606506375
333900499 557887778
I have used the function below, however it concatenates all the numbers together.
ALTER FUNCTION [dbo].[UDF_GetNumeric]
(#strAlphaNumeric VARCHAR(256))
RETURNS VARCHAR(256)
AS
BEGIN
DECLARE #intAlpha INT
SET #intAlpha = PATINDEX('%[^0-9]%', #strAlphaNumeric)
BEGIN
WHILE #intAlpha > 0
BEGIN
SET #strAlphaNumeric = STUFF(#strAlphaNumeric, #intAlpha, 1, '' )
SET #intAlpha = PATINDEX('%[^0-9]%', #strAlphaNumeric )
END
END
RETURN ISNULL(#strAlphaNumeric,0)
END
I'm using SQL Server 2012.

Upon looking further into this problem, I came up with -->
-- partition into non-num and numeric strings, collapse non-num into single space, and copy numeric as is
-- complicating: multiple non-num and multiple numeric strings
-- further, allow for starting with EITHER non-num or numeric
-- further, can have no numeric at all, or can have no non-num at all
I put data into table dbo.separatenumber
And created UDF--> Revised Jan 15th--del If/Then/Set #next, add Set #LeftMost
/****** Object: UserDefinedFunction [dbo].[fnSeparateNonNumericCharacters] Script Date: 01/14/2020 21:41:42 ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[fnSeparateNonNumericCharacters]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [dbo].[fnSeparateNonNumericCharacters]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE Function [dbo].[fnSeparateNonNumericCharacters](#strText VARCHAR(1000)) RETURNS VARCHAR(1000) AS
BEGIN
Declare #outText as varchar(1000), #LeftMost as char(4), #ndx as int
Set #outText = ''
IF PATINDEX('[0-9]', SUBSTRING(#strText,1,1)) = 1 -- is the 1st char numeric?
Set #LeftMost = 'Nums'
ELSE
Set #LeftMost = 'Text'
;
WHILE LEN(#strText) > 0
BEGIN
IF #LeftMost = 'Text'
BEGIN
Set #ndx = PATINDEX('%[0-9]%', #strText) -- where is the next Numeric
If #ndx = 0 Break -- bail when no more
Set #strText = SUBSTRING(#strText, #ndx, LEN(#strText) - #ndx + 1) -- bypass Text
Set #LeftMost = 'Nums'
END
ELSE -- #LeftMost = 'Nums'
BEGIN
Set #ndx = PATINDEX('%[^0-9]%', #strText) -- where is next Text
If #ndx = 0 Set #ndx = LEN(#strText) + 1 -- use EOL plus one when no more
Set #outText += SUBSTRING(#strText, 1, #ndx - 1) + ' ' -- Grab Numbers plus a space
If #ndx = LEN(#strText) + 1 Break -- bail when no more
Set #strText = SUBSTRING(#strText, #ndx, LEN(#strText) - #ndx + 1 ) -- move past this Num
Set #LeftMost = 'Text'
END
;
END
RETURN #outText -- here it is
END
GO
select
*
, dbo.fnSeparateNonNumericCharacters(clientname) as Numbers
from dbo.separatenumber
Sample output
ClientID ClientName Numbers
11 Mukherjee_ 2697231 Gehrmann _ 298053524 2697231 298053524
22 Butt Glen_740708968 Amanda_259055000 740708968 259055000
33 Quirk Michael_ 65941412 and Leanne _817498908 65941412 817498908
44 Butt Glen_740708968 Amanda_259055000 Tristan 3939393939 740708968 259055000 3939393939
55 Kryger Aaron _ 606506375 606506375
66 Krebs Paul
77 Haddrill Clare _ 333900499 McRedmond Patrick _557887778 333900499 557887778

Related

How to iterate over a string of varying length, replacing different abbreviations with their full text. All abbreviations separated by a semicolon

My problem is this; I have a field in a table that contains values like this:
NP
NP;MC;PE
MC;AB;AT;MI;TC;WM
OS
OG
I want to convert these abbreviations to their full name. i.e. NP becomes Nuclear Power, OG becomes Oil and Gas, MI becomes Military etc.
My desired output would be:
Nuclear Power
Nuclear Power;Military;Pesticides
and so on.
I'm creating this as a function. I got it working for just the one abbreviation and then the same for two. However my issue is that I may have 5 abbreviations or 7. I know my current approach is dreadful but cannot figure out how to loop it in the right way.
Please note: I've shortened the list of abbreviations for StackOverflow but there's 25 in total.
Please further note: I did the function bottom up (I don't know why) and got the two value and single value working. I've removed anything I did for values over 3 as nothing I did worked.
ALTER FUNCTION [dbo].[get_str_full]
(
-- Add the parameters for the function here
#str_input VARCHAR(250)
)
RETURNS VARCHAR(250)
AS
BEGIN
-- Declare the return variable here
DECLARE #Result VARCHAR(250)
DECLARE #TEMPSTRING VARCHAR(250)
DECLARE #TEMPSTRING_RIGHT AS VARCHAR(250)
-- DECLARE #PI_COUNT BIGINT
DECLARE #COUNTER INT
DECLARE #TOTAL_VALS BIGINT
DECLARE #STRING_ST VARCHAR(250)
DECLARE #POS_STR BIGINT
DECLARE #REMAINING_STR VARCHAR(250)
-- Used for easy loop skips
DECLARE #LEFTSKIP AS BIGINT
SET #LEFTSKIP = 1
SET #Result = #str_input
SET #STRING_ST = #Result
SET #COUNTER = (LEN(#Result) - LEN(REPLACE(#Result,';',''))) + 1
SET #TOTAL_VALS = (LEN(#Result) - LEN(REPLACE(#Result,';',''))) + 1
-- If the string has a semicolon then there's more than one PI value
IF CHARINDEX(';', #Result) > 0
BEGIN
WHILE #COUNTER > 0
BEGIN
IF #TOTAL_VALS >= 3 -- If counter is more than 2 then there's three or more
BEGIN
DECLARE #TEMP_VAL BIGINT
SET #TEMP_VAL = 5
END
ELSE IF #TOTAL_VALS = 2-- Theres 2
BEGIN
-- Do left two chars first
IF #LEFTSKIP = 1
BEGIN
SET #TEMPSTRING = LEFT(#Result, 2)
SELECT #TEMPSTRING = CASE #TEMPSTRING
WHEN 'MC' THEN 'Military Contracting'
WHEN 'NP' THEN 'Nuclear'
WHEN 'OG' THEN 'Oil & Gas'
WHEN 'OS' THEN 'Oil Sands'
WHEN 'PM' THEN 'Palm Oil'
WHEN 'PE' THEN 'Pesticides'
ELSE #TEMPSTRING
END
SET #LEFTSKIP = 2
END
ELSE IF #LEFTSKIP = 2
BEGIN
SET #TEMPSTRING_RIGHT = RIGHT(#Result, 2)
SELECT #TEMPSTRING_RIGHT = CASE #TEMPSTRING_RIGHT
WHEN 'MC' THEN 'Military Contracting'
WHEN 'NP' THEN 'Nuclear'
WHEN 'OG' THEN 'Oil & Gas'
WHEN 'OS' THEN 'Oil Sands'
WHEN 'PM' THEN 'Palm Oil'
WHEN 'PE' THEN 'Pesticides'
ELSE #TEMPSTRING_RIGHT
END
END
END
SET #COUNTER = #COUNTER - 1
END
SET #Result = CONCAT(#TEMPSTRING,';', #TEMPSTRING_RIGHT)
END
ELSE
BEGIN
SET #Result = REPLACE(#Result, 'MC', 'Military Contracting')
SET #Result = REPLACE(#RESULT, 'NP', 'Nuclear Power')
SET #Result = REPLACE(#Result, 'OG', 'Oil & Gas')
SET #Result = REPLACE(#Result, 'OS', 'Oil Sands')
SET #Result = REPLACE(#Result, 'PM', 'Palm Oil')
SET #Result = REPLACE(#Result, 'PE', 'Pesticides')
END
-- Return the result of the function
RETURN #Result
END
First for some easily consumable sample data:
DECLARE #tranlation TABLE(tCode VARCHAR(10), tString VARCHAR(40));
DECLARE #t TABLE(String VARCHAR(1000));
INSERT #t VALUES('PE;N'),('NP'),('NP;MC;PE;XX')
INSERT #tranlation VALUES ('N','Nukes'),('NP','Nuclear Power'),('MC','Military'),
('PE','Pesticides');
Note my updated sample data which includes "XX", which has no match , and an "N" for "Nukes" which would wreck any solution which leverages REPLACE. If you are on SQL 2016+ you can use STRING_SPLIT and STRING_AGG.
SELECT
OldString = t.String,
NewString = STRING_AGG(ISNULL(tx.tString,items.[value]),';')
FROM #t AS t
OUTER APPLY STRING_SPLIT(t.String,';') AS items
LEFT JOIN #tranlation AS tx
ON items.[value] = tx.tCode
GROUP BY t.String ;
Returns:
OldString NewString
----------------- -------------------------------------------
NP Nuclear Power
NP;MC;PE;XX Nuclear Power;Military;Pesticides;XX
PE;N Pesticides;Nukes
You should really fix your table design so that you do not store multiple pieces of info in one column.
If you would like it as a function, I would strongly recommend an inline Table-Valued function rather than a scalar function.
If you have SQL Server version 2017+ you can use STRING_SPLIT and STRING_AGG for this.
CREATE OR ALTER FUNCTION GetFullStr
( #str varchar(250) )
RETURNS TABLE
AS RETURN
(
SELECT STRING_AGG(ISNULL(v.FullStr, s.value), ';') result
FROM STRING_SPLIT(#str, ';') s
LEFT JOIN (VALUES
('MC', 'Military Contracting'),
('NP', 'Nuclear'),
('OG', 'Oil & Gas'),
('OS', 'Oil Sands'),
('PM', 'Palm Oil'),
('PE', 'Pesticides')
) v(Abbr, FullStr) ON v.Abbr = s.value
);
GO
You can, and should, replace the VALUES with a real table.
On 2016 you would need FOR XML PATH instead of STRING_AGG:
CREATE OR ALTER FUNCTION GetFullStr
( #str varchar(250) )
RETURNS TABLE
AS RETURN
(
SELECT STUFF(
(SELECT ';' + ISNULL(v.FullStr, s.value)
FROM STRING_SPLIT(#str, ';') s
LEFT JOIN (VALUES
('MC', 'Military Contracting'),
('NP', 'Nuclear'),
('OG', 'Oil & Gas'),
('OS', 'Oil Sands'),
('PM', 'Palm Oil'),
('PE', 'Pesticides')
) v(Abbr, FullStr) ON v.Abbr = s.value
FOR XML PATH(''), TYPE
).value('text()[1]','varchar(2500)'),
, 1, 1, '')
);
GO
You use it like this:
SELECT s.result AS FullStr
FROM table
OUTER APPLY GetFullStr(value) AS s;
-- alternatively
SELECT (SELECT * FROM GetFullStr(value)) AS FullStr
FROM table;
You could assign your abbreviation mappings to a TABLE variable and then use that for your REPLACE. You could build this into a function, then pass your string values in.
The test below returns Military:Nuclear Power:XX.
declare #mapping table (abbrev varchar(50), fullname varchar(100))
insert into #mapping(abbrev, fullname)
values ('NP','Nuclear Power'),
('MC','Military')
declare #testString varchar(100), #newString varchar(100)
set #teststring = 'MC:NP:XX'
set #newString = #testString
SELECT #newString = REPLACE(#newString, abbrev, fullname) FROM #mapping
select #newString

Remove duplicate detail transaction (header detail store procedure)

I have problem when creating header detail transaction in store procedure. Assume 1 header contain 3 details transaction. If I want to get invoice I must join some table for getting the formula.
USE [M_TENANT]
GO
/****** Object: StoredProcedure [dbo].[generate_billingv2] Script Date: 07/02/2020 09:32:42 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[generate_billingv2]
AS
--exec generate_billingv2
SET NOCOUNT ON;
BEGIN TRANSACTION
DECLARE #genbill_nochar INT
,#OPT_UTILITY_NOCHAR NVARCHAR(50)
,#NAME_CHAR VARCHAR(80)
,#opt_utility_detail NVARCHAR(50)
,#MD_BILLING_ID_INT INT
,#BILLING_ID_UTILITY INT
,#OPT_UTILITY_AMT NUMERIC
,#BILLING_ID_FORMULA INT
,#FORMULA_PRICE NUMERIC
,#FORMULA_VA NUMERIC
,#FORMULA_NAME VARCHAR(50)
,#MD_FORMULA_PERCENTAGE DECIMAL(18, 3)
,#bill_TYPE INT
,#BASE_INVOICE_AMT NUMERIC
,#OPT_UTILITY_USED NUMERIC
,#ABODEMEN NUMERIC
,#UNIT_LB DECIMAL(18, 3)
,#TAX_UTILITY NUMERIC(18, 3)
,#TOTAL_UTILITY NUMERIC(18, 3)
,#OPT_GENBILL_NOCHAR VARCHAR(50)
,#NOUNIT_CHAR CHAR(20)
,#OPT_GENBILL_STATUS_INT INT
,#OPT_GENBILL_TRX_DATE DATE
,#OPT_UTILITY_TRX_DATE DATE
,#OPT_TRANS_ID_INT INT
,#OPT_GENERATE_BY VARCHAR(50)
,#MD_FORMULA_PRICE NUMERIC
,#USAGE DECIMAL(18, 2)
,#OPT_FLOOR CHAR(10)
,#MD_FORMULA_NAME VARCHAR(50)
,#OPT_START NUMERIC
,#OPT_BILL_END NUMERIC
,#OPT_START_DATE DATE
,#OPT_END_DATE DATE
,#FORMULA_PERCENTAGE DECIMAL(18, 2)
SET #BASE_INVOICE_AMT = 0
SET #TAX_UTILITY = 0
SET #TOTAL_UTILITY = 0
SET #OPT_GENBILL_STATUS_INT = 0
SET #OPT_GENBILL_TRX_DATE = GETDATE()
SET #OPT_GENERATE_BY = 'AUTO'
DECLARE bill_header CURSOR
FOR
SELECT a.OPT_UTILITY_NOCHAR
,a.NOUNIT_CHAR
,b.UNIT_LB
,b.NAME_CHAR
,b.OPT_FLOOR
,a.OPT_TRANS_ID_INT
,a.OPT_UTILITY_TRX_DATE
,0 AS BASE_INVOICE
,0 AS TAX_UTILITY
,0 AS TOTAL_ULTILITY
FROM OPT_UTILITY a
INNER JOIN OPT_TRANS b ON a.OPT_TRANS_ID_INT = b.OPT_TRANS_ID_INT
WHERE a.OPT_GENBILL_STATUS_INT = 0
OPEN bill_header
FETCH NEXT
FROM bill_header
INTO #OPT_UTILITY_NOCHAR
,#NOUNIT_CHAR
,#UNIT_LB
,#NAME_CHAR
,#OPT_FLOOR
,#OPT_TRANS_ID_INT
,#OPT_UTILITY_TRX_DATE
,#BASE_INVOICE_AMT
,#TAX_UTILITY
,#TOTAL_UTILITY
WHILE ##FETCH_STATUS = 0
BEGIN
--HEADER TRANSACTION
--PRINT 'ini header'+'-'+ #OPT_UTILITY_NOCHAR
SET #OPT_GENBILL_NOCHAR = convert(VARCHAR, (
SELECT 'KALINV' + convert(VARCHAR(4), YEAR(GETDATE())) + REPLICATE('0', 5 - LEN(RTRIM(invoiced_count))) + RTRIM(invoiced_count)
FROM counter_table
));
INSERT INTO OPT_GENBILL (
OPT_GENBILL_NOCHAR
,OPT_UTILITY_NOCHAR
,NOUNIT_CHAR
,NAME_CHAR
,LB
,BASE_UTILITY
,TAX_UTILITY
,TOTAL_UTILITY
,OPT_GENBILL_STATUS_INT
,OPT_GENBILL_TRX_DATE
,OPT_UTILITY_TRX_DATE
,OPT_TRANS_ID_INT
,OPT_GENERATE_BY
)
VALUES (
#OPT_GENBILL_NOCHAR
,#OPT_UTILITY_NOCHAR
,#NOUNIT_CHAR
,#NAME_CHAR
,#UNIT_LB
,#BASE_INVOICE_AMT
,#TAX_UTILITY
,#TOTAL_UTILITY
,#OPT_GENBILL_STATUS_INT
,#OPT_GENBILL_TRX_DATE
,#OPT_UTILITY_TRX_DATE
,#OPT_TRANS_ID_INT
,#OPT_GENERATE_BY
)
DECLARE bill_detail CURSOR
FOR
SELECT C.MD_BILLING_ID_INT AS BILL_TYPE
,a.OPT_UTILITY_NOCHAR
,a.MD_BILLING_ID_INT
,b.MD_FORMULA_PRICE
,b.MD_FORMULA_NAME
,b.MD_FORMULA_PERCENTAGE
,b.MD_FORMULA_PJU_ABD AS ABODEMEN
,b.MD_FORMULA_VA AS FORMULA_VA
,a.OPT_BILL_END - a.OPT_UTILITY_AMT AS OPT_START
,a.OPT_BILL_END
,a.OPT_UTILITY_AMT AS USAGE
,a.OPT_START_DATE
,a.OPT_END_DATE
FROM OPT_UTILITY_DETAIL a
INNER JOIN MD_FORMULA b ON a.MD_BILLING_ID_INT = b.MD_FORMULA_ID_INT
INNER JOIN MD_BILLING_TYPE c ON b.MD_BILLING_ID_INT = c.MD_BILLING_ID_INT
WHERE a.OPT_UTILITY_NOCHAR = #OPT_UTILITY_NOCHAR
OPEN bill_detail
FETCH NEXT
FROM bill_detail
INTO #BILL_TYPE
,#OPT_UTILITY_NOCHAR
,#MD_BILLING_ID_INT
,#MD_FORMULA_PRICE
,#MD_FORMULA_NAME
,#MD_FORMULA_PERCENTAGE
,#ABODEMEN
,#FORMULA_VA
,#OPT_START
,#OPT_BILL_END
,#USAGE
,#OPT_START_DATE
,#OPT_END_DATE
--IF exists(select TOP 1* from OPT_GENBILL where OPT_UTILITY_NOCHAR=#OPT_UTILITY_NOCHAR)
--BEGIN
-- ROLLBACK TRANSACTION
-- DEALLOCATE bill_detail
-- RAISERROR('invoice sudah pernah generate ',16,-1,#OPT_UTILITY_NOCHAR)
-- RETURN
--END
IF ##FETCH_STATUS <> 0
PRINT ' <<None>>'
WHILE ##FETCH_STATUS = 0
BEGIN
--SET #BASE_INVOICE_AMT = CASE WHEN #BILL_TYPE=3 AND #USAGE<=40 THEN
-- ((#ABODEMEN*(#FORMULA_VA/1000)*#FORMULA_PRICE)+ ((#ABODEMEN*(#FORMULA_VA/1000)*#FORMULA_PRICE)*#FORMULA_PERCENTAGE))
-- when #bill_TYPE=3 and #USAGE>40 then
-- ((#USAGE*(#FORMULA_VA/1000)*#FORMULA_PRICE)+ ((#USAGE*(#FORMULA_VA/1000)*#FORMULA_PRICE)*#FORMULA_PERCENTAGE))
-- when #bill_TYPE=2 then ((#USAGE*#FORMULA_PRICE)+#ABODEMEN)
-- when #bill_TYPE=1 then #UNIT_LB*#FORMULA_PRICE
-- else 0 end
--print #OPT_UTILITY_NOCHAR
-- print #BILL_TYPE
-- print #USAGE
-- print #ABODEMEN
-- print #FORMULA_PRICE
-- print #FORMULA_VA
-- print #FORMULA_PERCENTAGE
INSERT INTO OPT_GENBILL_DETAIL (
OPT_UTILITY_NOCHAR
,NOUNIT_CHAR
,OPT_START_DATE
,OPT_END_DATE
,OPT_BILL_START
,OPT_BILL_END
,OPT_UTILITY_AMT
,OPT_GENBILL_NOCHAR
)
SELECT #OPT_UTILITY_NOCHAR
,#NOUNIT_CHAR
,OPT_START_DATE
,OPT_END_DATE
,OPT_BILL_END - OPT_UTILITY_AMT
,OPT_BILL_END
,CASE
WHEN #BILL_TYPE = 3
AND #USAGE <= 40
THEN ((#ABODEMEN * (#FORMULA_VA / 1000) * #FORMULA_PRICE) + ((#ABODEMEN * (#FORMULA_VA / 1000) * #FORMULA_PRICE) * #FORMULA_PERCENTAGE))
WHEN #bill_TYPE = 3
AND #USAGE > 40
THEN ((#USAGE * (#FORMULA_VA / 1000) * #FORMULA_PRICE) + ((#USAGE * (#FORMULA_VA / 1000) * #FORMULA_PRICE) * #FORMULA_PERCENTAGE))
WHEN #bill_TYPE = 2
THEN ((#USAGE * #FORMULA_PRICE) + #ABODEMEN)
ELSE 0
END
,#OPT_GENBILL_NOCHAR
FROM OPT_UTILITY_DETAIL
WHERE OPT_UTILITY_NOCHAR = #OPT_UTILITY_NOCHAR
FETCH NEXT
FROM bill_detail
INTO #BILL_TYPE
,#OPT_UTILITY_NOCHAR
,#MD_BILLING_ID_INT
,#MD_FORMULA_PRICE
,#MD_FORMULA_NAME
,#MD_FORMULA_PERCENTAGE
,#ABODEMEN
,#FORMULA_VA
,#OPT_START
,#OPT_BILL_END
,#USAGE
,#OPT_START_DATE
,#OPT_END_DATE
END
CLOSE bill_detail
DEALLOCATE bill_detail
UPDATE counter_table
SET invoiced_count = invoiced_count + 1
UPDATE OPT_UTILITY
SET OPT_GENBILL_STATUS_INT = 1
WHERE OPT_UTILITY_NOCHAR = #OPT_UTILITY_NOCHAR
-- Get the next vendor.
FETCH NEXT
FROM bill_header
INTO #OPT_UTILITY_NOCHAR
,#NOUNIT_CHAR
,#UNIT_LB
,#NAME_CHAR
,#OPT_FLOOR
,#OPT_TRANS_ID_INT
,#OPT_UTILITY_TRX_DATE
,#BASE_INVOICE_AMT
,#TAX_UTILITY
,#TOTAL_UTILITY
END
CLOSE bill_header;
DEALLOCATE bill_header;
COMMIT TRANSACTION
RETURN
But the result 3 detail generating 9 details rows.

Unicode (Hexadecimal) to varchar conversion

Here is the problem, the system I use can create a saved search which basically generates a 'Where' clause and saves it in the database as type Image ..
I am trying to convert the image entry to a readable format, it is saved in 2 forms (Unicode and non unicode) now I can get the non unicode entries fine and they display correctly, however when I try and convert the Unicode entries it does not display correctly an example of what I am trying to convert is
0x01000000FFFEFF00FFFEFF0001050000FFFEFF05510075006F007400650006000000060000000100000001000000000000000000000080000000000000FD00000000000000000700000001050000FFFEFF254E006F0072006700720065006E005F00470072006F007500700020004900640020003D00200030007800300030003000300030003000300030003000300030003000300030003200330004000000060000000100000002000000000000000000002380000000000022B00000000000000001000000FFFEFF5454005400490044005F003400330034005200390032003300370020005F005F00530051004C005F00440045004C0049004D005F005F002000510075006F00740065005F002E004E006F0072006700720065006E005F00470072006F00750070005F004900640020003D00200054005400490044005F00340033003400520039003200330037002E004E006F0072006700720065006E005F00470072006F00750070005F00490064000000000001050000FFFEFF0C45006D0070006C006F0079006500650020003D0020003F0004000000060000000100000002000000000000000000000080000000000001030101000000000001000000FFFEFFA754005400490044005F00320035005200310032003400350034002E0054005400490044005F0032003300520038003600340052003100320034003500340020005F005F00530051004C005F00440045004C0049004D005F005F002000510075006F00740065005F002E0053006800690070005F0054006F005F0043006F006D00700061006E0079005F004900640020003D00200054005400490044005F00320035005200310032003400350034002E0043006F006D00700061006E0079005F0049006400200041004E004400200054005400490044005F00320035005200310032003400350034002E004100630063006F0075006E0074005F004D0061006E0061006700650072005F004900640020003D00200054005400490044005F003200330052003800360034005200310032003400350034002E0045006D0070006C006F007900650065005F00490064000000000001050000FFFEFF0C45006D0070006C006F0079006500650020003D0020003F0004000000060000000100000002000000000000000000000080000000000001030101000000000001000000FFFEFFB354005400490044005F00320035005200310032003400350034002E0054005400490044005F00320033005200380037003000390052003100320034003500340020005F005F00530051004C005F00440045004C0049004D005F005F002000510075006F00740065005F002E0053006800690070005F0054006F005F0043006F006D00700061006E0079005F004900640020003D00200054005400490044005F00320035005200310032003400350034002E0043006F006D00700061006E0079005F0049006400200041004E004400200054005400490044005F00320035005200310032003400350034002E0049006E007400650072006E0061006C005F0043006F006D006D00650072006300690061006C005F00530061006C00650073005F004900640020003D00200054005400490044005F0032003300520038003700300039005200310032003400350034002E0045006D0070006C006F007900650065005F00490064000000000001050000FFFEFF13510075006F0074006500200054006F00740061006C0020003E003D00200032003000300030000400000006000000010000000200000000000000000000008000000000001847010101080000000000000000409F400000000001000000FFFEFF15510075006F00740065005F0020005F005F00530051004C005F00440045004C0049004D005F005F0020000000000001050000FFFEFF1F46006F006C006C006F007700200055007000200053007400610074007500730020003D00200054006F00200046006F006C006C006F007700200055007000040000000600000001000000020000000000000000000000800000000000392F0000000000000001000000FFFEFF15510075006F00740065005F0020005F005F00530051004C005F00440045004C0049004D005F005F0020000200000001050000FFFEFF1F46006F006C006C006F007700200055007000200053007400610074007500730020003D00200049006E00200046006F006C006C006F007700200055007000050000000600000001000000020000000000000000000000800000000000392F0000000000000001000000FFFEFF15510075006F00740065005F0020005F005F00530051004C005F00440045004C0049004D005F005F0020000000000001050000FFFEFF1F46006F006C006C006F007700200055007000200053007400610074007500730020003D0020004E006F00200046006F006C006C006F007700200055007000050000000600000001000000020000000000000000000000800000000000392F0000000000000001000000FFFEFF15510075006F00740065005F0020005F005F00530051004C005F00440045004C0049004D005F005F0020000000000001050000FFFEFF20510075006F0074006500200046006F006C006C006F00770020004500780070006900720065007300200049006E002000440061007900730020003E002000310004000000060000000100000002000000000000000000000080000000000039DD0000000000000001000000FFFEFF4854005400490044005F003700310035004C003100340034003600330020005F005F00530051004C005F00440045004C0049004D005F005F002000510075006F00740065005F002E00510075006F00740065005F005F004900640020003D00200054005400490044005F003700310035004C00310034003400360033002E00510075006F00740065005F005F00490064000000000001050000FFFEFF11510075006F00740065005F0020004900640020004E006F007400200049006E00200004000000060000000100000002000000000000000000000080000000000018F5000000040000000100000000000000000000000000000001000000FFFEFF15510075006F00740065005F0020005F005F00530051004C005F00440045004C0049004D005F005F0020000000000003000000010000000000000000002F9680000000000018F5000000000000000000000000
the SQL code I am using to convert is the following
with saved_lookups_cte as
(select
table_id,
table_name,
saved_lookups_id,
saved_lookup_name,
case
when charindex('WhereDelim',query_text) > 0 then
substring(query_text,len(query_text) - charindex(reverse('WhereDelim'),reverse(query_text)) + 3,4000)
else query_text
end query_text
, sql_tree_binary
from (select
table_id,
table_name,
saved_lookups_id,
saved_lookup_name,
case isUnicode
when 1 then [Production_ED].dbo.[RemoveNonASCII] (cast(cast(substring(sql_tree_binary, startIndex, queryLength * 2) as nvarchar(max))as varchar(max)))
else cast(substring(sql_tree_binary, startIndex, queryLength) as varchar(8000))
end query_text
, sql_tree_binary
from (
select
saved_lookup_name,
case
when substring(sql_tree_binary,1,5) = 0x0100000000 then 0
when substring(sql_tree_binary,1,5) = 0x01000000FF then 1
end isUnicode,
cast(case
when substring(sql_tree_binary,1,5) = 0x0100000000 then
case
when substring(sql_tree_binary,6,1) = 0xFF then substring(sql_tree_binary,8,1) + substring(sql_tree_binary,7,1)
else substring(sql_tree_binary,6,1)
end
when substring(sql_tree_binary,1,5) = 0x01000000FF then
case
when substring(sql_tree_binary,12,1) = 0xFF then substring(sql_tree_binary,14,1) + substring(sql_tree_binary,13,1)
else substring(sql_tree_binary,12,1)
end
end as int) queryLength,
case
when substring(sql_tree_binary,1,5) = 0x0100000000 then
case
when substring(sql_tree_binary,6,1) = 0xFF then 9
else 7
end
when substring(sql_tree_binary,1,5) = 0x01000000FF then
case
when substring(sql_tree_binary,12,1) = 0xFF then 15
else 13
end
end startIndex,
s.table_id,
t.table_name,
s.saved_lookups_id,
s.sql_tree_binary
from
Production_Ed.dbo.Saved_Lookups s inner join
tables t on s.table_id = t.tables_id
-- where substring(saved_lookups_id,1,1) <> 0x00
where saved_lookup_name = 'DE Quotes Open Account Manager >=2000'
) x
) y
)
select * from saved_lookups_cte
The part of the query that does the conversion is
when 1 then [Production_ED].dbo.[RemoveNonASCII]
(cast(cast(substring(sql_tree_binary, startIndex, queryLength * 2) as
nvarchar(max))as varchar(max)))
now this actually returns nothing, however if I set the startIndex to 17 and change the queryLength to 3000 * 2 (unicode byte = 2) I get
??Quote?????Norgren_Group Id = 0x0000000000000023???A??????????????? ????????????? ??????????????????????? ? ??????????????????????????????A?????????? ? ???A??Aa??TTID_25R12454.TTID_23R864R12454 __SQ
Returned, although I can read parts, it is not the full query ... yet even if I extend the length I get no more.
Any help would be greatly appreciated.
Code for the RemoveNonASCII function:
ALTER FUNCTION [dbo].[RemoveNonASCII]
(
#nstring nvarchar(max)
)
RETURNS varchar(max)
AS
BEGIN
DECLARE #Result varchar(max)
SET #Result = ''
DECLARE #nchar nvarchar(1)
DECLARE #position int
SET #position = 1
WHILE #position <= LEN(#nstring)
BEGIN
SET #nchar = SUBSTRING(#nstring, #position, 1)
IF ASCII(#nchar) between 32 and 255
SET #Result = #Result + #nchar
SET #position = #position + 1
END
RETURN #Result
END
GO
Ok, so I found the issue, inside the hex string there were null values, which caused the rest of the returned varchar string to become null .. So I just changed the function to:
AS
BEGIN
DECLARE #Result varchar(max)
SET #Result = ''
DECLARE #nchar nvarchar(1)
DECLARE #position int
SET #position = 1
WHILE #position <= LEN(#nstring)
BEGIN
SET #nchar = SUBSTRING(#nstring, #position, 1)
IF ASCII(#nchar) between 1 and 125
SET #Result = #Result + #nchar
SET #position = #position + 1
END
RETURN #Result
END
Eradicating 0 being the ASCII Null value!

Selecting First String from Record SQL

I have a query which so far returns the following;
Stock Code BomReference Description
2134601A 5134601A ***DISC*** 004601 EXP Pack I PC Spoo (NF) 500MLX6
2134601A 5109052 40010934 IPC2101 UK PACK PC SHAMPOO (NF) 500MLX6
2134601A 5134601B 40010908 004601 EXP PACK PC SHAMPOO 500MLX6
2134601A 5109052L 40010909 IPC2101L UK PACK IPC SPOO 500ML X 6
The code is as follows;
SELECT BomComponents.StockCode, BomHeaders.BomReference, BomHeaders.Description
FROM BomComponents INNER JOIN
BomHeaders ON BomComponents.HeaderID = BomHeaders.ID
WHERE StockCode = '2134601A'
I want to be able to select just the first word/number from Description and then group the bom reference and Description together to result in the following.
StockCode BomReference Description
2134601A 5134601A, 5109052, 5134601B, 5109052L ***DISC***, 40010934, 40010908, 40010909
Any help would be massively helpful.
Creating the function below should accomplish this for you. I use it VERY frequently.
select dbo.getTokenValue([Your String], [Delimiting Character], [Position])
In this case:
select dbo.getTokenValue(Description, ' ', 1)
/****** Object: UserDefinedFunction [dbo].[getTokenValue] Script Date: 7/8/2014 1:08:08 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
Accepts the string, delimeter and the position of the required value and returns the value
*/
create function [dbo].[getTokenValue] (#tokenvalue varchar(200), #Delimeter char, #pos int)
returns varchar(200)
Begin
Declare #DelimPos int
Declare #remSubstr varchar(200)
Declare #FinalStr varchar(200)
Declare #Count int
Declare #Countdelim int
set #Finalstr = ''
Set #Countdelim = 0
Set #remSubstr = #tokenValue
Set #Count = #pos-1
set #countdelim = 1
while #Count <> 0
Begin
Set #DelimPos = charindex(#Delimeter,#remSubstr)
If #DelimPos = 0
Break;
set #remSubstr = substring(#remSubstr,#DelimPos+1,Len(#remSubstr)-#DelimPos)
set #Count = #Count -1
set #CountDelim = #CountDelim + 1
End
If #Pos > #CountDelim
Begin
set #Finalstr = null
return #FinalStr
end
else
Begin
Set #DelimPos = charindex(#Delimeter,#remSubstr)
if #DelimPos = 0
Set #Finalstr = #remsubstr
else
Set #FinalStr = substring(#remSubstr,1,#DelimPos-1)
end
return #FinalStr
end
GO

How can I write this T-SQL cursor?

I have multiple values in one cell in a table which are separated by an space from each other. this is somehow how my table looks like, there is a space in between each string in every cell:
column1 | column2
|
abc fgt | rty lkj
I want to create another table based on the first table in which "abc" and "rty" are in one row because they both are located in the first place, "fgt" and "lkj" are in another row for the same relational reason (they are in the 2nd place and so on):
column1 | column2
|
abc | rty
fgt | lkj
How can I do that?
You can use a function like this
IF EXISTS(SELECT * FROM sysobjects WHERE ID = OBJECT_ID('UF_CSVToTable'))
DROP FUNCTION UF_CSVToTable
GO
CREATE FUNCTION UF_CSVToTable
(
#psCSString VARCHAR(8000)
)
RETURNS #otTemp TABLE(sID VARCHAR(20),tID VARCHAR(20))
AS
BEGIN
DECLARE #sTemp VARCHAR(10)
DECLARE #tTemp VARCHAR(10)
WHILE LEN(#psCSString) > 0
BEGIN
SET #sTemp = LEFT(#psCSString, ISNULL(NULLIF(CHARINDEX(' ', #psCSString) - 1, -1),
LEN(#psCSString)))
SET #psCSString = SUBSTRING(#psCSString,ISNULL(NULLIF(CHARINDEX(' ', #psCSString), 0),
LEN(#psCSString)) + 1, LEN(#psCSString))
INSERT INTO #otTemp(sID) VALUES (#sTemp)
SET #tTemp = LEFT(#psCSString, ISNULL(NULLIF(CHARINDEX(' ', #psCSString) - 1, -1),
LEN(#psCSString)))
SET #psCSString = SUBSTRING(#psCSString,ISNULL(NULLIF(CHARINDEX(' ', #psCSString), 0),
LEN(#psCSString)) + 1, LEN(#psCSString))
UPDATE #otTemp SET tID=#tTemp WHERE sID=#sTemp
END
RETURN
END
Go
It can be called like this.
select * from UF_CSVToTable('1 2 3 4 5 6 7 15 55 59 86')
You need to pass your column as input parameter.
SQL FIDDLE DEMO
First of all, you can create UDF for splitting values by specific delimiter (in your case this is SPACE):
CREATE FUNCTION [dbo].[Split](#String nvarchar(4000), #Delimiter char(1))
returns #temptable TABLE (rownumber INT , items nvarchar(4000))
as
begin
declare #idx int
declare #slice nvarchar(4000)
DECLARE #rownumber int = 1
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(rownumber, Items) values(#rownumber, #slice)
set #String = right(#String,len(#String) - #idx)
SET #rownumber = #rownumber + 1
if len(#String) = 0 break
end
return
end
GO
After that, it is enough to write simple INSERT INTO SELECT... query:
INSERT INTO dbo.Table_2
( column1, column2 )
SELECT
item1.items ,
item2.items
FROM dbo.Split((SELECT column1 FROM dbo.Table_1), SPACE(1)) AS item1
FULL JOIN dbo.Split((SELECT column2 FROM dbo.Table_1), SPACE(1)) AS item2
ON item1.rownumber = item2.rownumber
Table_1 is table where actually values are, Table_2 is table for final rows.
SQL Fiddle Demo

Resources