TSQL dbo.split including a key - tsql

So I have the function below. My question is how can I get the following query to use the function to to create a view. I'm trying to get p_c_id to be the #ValueID and notes to be the #List.
select p_c_id, notes from dbo.product
create FUNCTION [dbo].[Split2Value]
( #Delimiter varchar(5),
#List varchar(8000),
#ValueID bigint
)
RETURNS #TableOfValues table
( RowID smallint IDENTITY(1,1),
[Value] varchar(500),
ValueID bigint
)
AS
BEGIN
DECLARE #LenString int
WHILE len( #List ) > 0
BEGIN
SELECT #LenString =
(CASE charindex( #Delimiter, #List )
WHEN 0 THEN len( #List )
ELSE ( charindex( #Delimiter, #List ) -1 )
END
)
INSERT INTO #TableOfValues
SELECT substring( #List, 1, #LenString ), #ValueID
SELECT #List =
(CASE ( len( #List ) - #LenString )
WHEN 0 THEN ''
ELSE right( #List, len( #List ) - #LenString - 1 )
END
)
END
RETURN
END

select
SV.RowID,
SV.[Value],
ValueID
from dbo.product as P
cross apply dbo.Split2Value('DELI?', P.notes, P.p_c_id) as SV

Related

insert with multiple subinserts - reference return value from previous subinsert in a following subinsert

I have a series of tables, each referencing the serial id from the preceding one. Is there a way to insert into all of them with a single statement? I have tried
WITH ins1 AS ( INSERT INTO tab1 ( col ) VALUES ( 'val' ) RETURNING tab1.id AS tab1id ),
ins2 AS ( INSERT INTO tab2 ( col ) VALUES ( tab1id ) RETURNING tab2.id AS tab2id )
INSERT INTO finaltab ( col ) VALUES ( tab2id );
but WITH clause values are only available in the final insert.
Trying
WITH ins2 AS (
INSERT INTO tab2 ( col )
SELECT tab1id FROM (
WITH ins1 AS (
INSERT INTO tab1 ( col )
VALUES ( 'val' )
RETURNING tab1.id AS tab1id
)
SELECT tab1id
)
RETURNING tab2.id AS tab2id
)
INSERT INTO finaltab ( col ) VALUES ( tab2id );
does not work because data-modifying WITH clauses must be top-level.
Is there a way to do this?
You need to select from the CTEs:
WITH ins1 AS (
INSERT INTO tab1 (col)
VALUES ('val')
RETURNING tab1.id AS tab1id
), ins2 AS (
INSERT INTO tab2 (col)
select tab1id
from ins1
RETURNING tab2.id AS tab2id
)
INSERT INTO finaltab (col)
select tab2id
from ins2;

TSQL - Convert Money to Spanish Text

I have come across a very cool function from another source that translates money data types to English Text. It's great, but I also need to do this in Spanish. I tried to edit the numbers to Spanish words but of course the "rules" of Spanish numbering aren't the same as English. Does anyone have something already for converting a money data type to a Spanish text? Below is the one for English for reference. Or can a Spanish speaking db dev help me out here with modifying this one?
CREATE FUNCTION [dbo].[fnNumberToEnglish](#Money AS money)
RETURNS VARCHAR(1024)
AS
BEGIN
DECLARE #Number as BIGINT
SET #Number = FLOOR(#Money)
DECLARE #Below20 TABLE (ID int identity(0,1), Word varchar(32))
DECLARE #Below100 TABLE (ID int identity(2,1), Word varchar(32))
INSERT #Below20 (Word) VALUES
( 'Zero'), ('One'),( 'Two' ), ( 'Three'),
( 'Four' ), ( 'Five' ), ( 'Six' ), ( 'Seven' ),
( 'Eight'), ( 'Nine'), ( 'Ten'), ( 'Eleven' ),
( 'Twelve' ), ( 'Thirteen' ), ( 'Fourteen'),
( 'Fifteen' ), ('Sixteen' ), ( 'Seventeen'),
('Eighteen' ), ( 'Nineteen' )
INSERT #Below100 VALUES ('Twenty'), ('Thirty'),('Forty'), ('Fifty'),
('Sixty'), ('Seventy'), ('Eighty'), ('Ninety')
DECLARE #English varchar(1024) =
(
SELECT Case
WHEN #Number = 0 THEN ''
WHEN #Number BETWEEN 1 AND 19
THEN (SELECT Word FROM #Below20 WHERE ID=#Number)
WHEN #Number BETWEEN 20 AND 99
-- SQL Server recursive function
THEN (SELECT Word FROM #Below100 WHERE ID=#Number/10)+ '-' +
dbo.fnMoneyToEnglish( #Number % 10)
WHEN #Number BETWEEN 100 AND 999
THEN (dbo.fnMoneyToEnglish( #Number / 100))+' Hundred '+
dbo.fnMoneyToEnglish( #Number % 100)
WHEN #Number BETWEEN 1000 AND 999999
THEN (dbo.fnMoneyToEnglish( #Number / 1000))+' Thousand '+
dbo.fnMoneyToEnglish( #Number % 1000)
WHEN #Number BETWEEN 1000000 AND 999999999
THEN (dbo.fnMoneyToEnglish( #Number / 1000000))+' Million '+
dbo.fnMoneyToEnglish( #Number % 1000000)
ELSE ' INVALID INPUT' END
)
SELECT #English = RTRIM(#English)
SELECT #English = RTRIM(LEFT(#English,len(#English)-1))
WHERE RIGHT(#English,1)='-'
IF ##NestLevel = 1
BEGIN
SELECT #English = #English+' POINT '
SELECT #English = #English+
convert(varchar,convert(int,100*(#Money - #Number)))
END
RETURN (#English)
END
So I just learned Spanish and did it myself. Enjoy!
ALTER FUNCTION [dbo].[fnMoneyToSpanish](#Money AS money)
RETURNS VARCHAR(1024)
AS
BEGIN
DECLARE #Number as BIGINT
SET #Number = FLOOR(#Money)
DECLARE #Below20 TABLE (ID int identity(0,1), Word varchar(32))
DECLARE #Below100 TABLE (ID int identity(2,1), Word varchar(32))
INSERT #Below20 (Word) VALUES
( 'cero'), ('uno'),( 'dos' ), ( 'tres'),
( 'cuatro' ), ( 'cinco' ), ( 'seis' ), ( 'siete' ),
( 'ocho'), ( 'nueve'), ( 'diez'), ( 'once' ),
( 'doce' ), ( 'trece' ), ( 'catorce'),
( 'quince' ), ('dieciséis' ), ( 'diecisiete'),
('dieciocho' ), ( 'diecinueve' )
INSERT #Below100 VALUES ('veinti'), ('treinta'),('cuarenta,'), ('cincuenta'),
('sesenta'), ('setenta'), ('ochenta'), ('coventa')
DECLARE #English varchar(1024) =
(
SELECT Case
WHEN #Number = 0 THEN ''
WHEN #Number BETWEEN 1 AND 19
THEN (SELECT Word FROM #Below20 WHERE ID=#Number)
WHEN #Number BETWEEN 20 AND 99
THEN (SELECT CASE WHEN WORD = 'veinti' AND #Number = '20' THEN 'viente' ELSE WORD END FROM(SELECT Word FROM #Below100 WHERE ID=#Number/10)d) + CASE WHEN ##NestLevel in (3,4) AND (SELECT Word FROM #Below100 WHERE ID=#Number/10) <> 'veinti' THEN ' y ' ELSE '' END + --concat(' Number:',#Number,' Level:', ##NestLevel, ' ') +
dbo.fnMoneyToSpanish( #Number % 10)
WHEN #Number BETWEEN 100 AND 999
THEN CASE WHEN #Number < 200 THEN ' ciento ' ELSE (dbo.fnMoneyToSpanish( #Number / 100)) + 'cientos ' END +
dbo.fnMoneyToSpanish( #Number % 100)
WHEN #Number BETWEEN 1000 AND 999999
THEN CASE WHEN #Number < 2000 THEN ' mil ' ELSE (dbo.fnMoneyToSpanish( #Number / 1000)) + ' mil ' END +
dbo.fnMoneyToSpanish( #Number % 1000)
WHEN #Number BETWEEN 1000000 AND 999999999
THEN CASE WHEN #Number < 200000 THEN ' millón ' ELSE (dbo.fnMoneyToSpanish( #Number / 1000000)) + ' millones ' END +
dbo.fnMoneyToSpanish( #Number % 1000000)
ELSE ' INVALID INPUT' END
)
SELECT #English = RTRIM(#English)
SELECT #English = RTRIM(LEFT(#English,len(#English)-1))
WHERE RIGHT(#English,1)=' y '
IF ##NestLevel = 1
BEGIN
SELECT #English = #English+' dólares y '
SELECT #English = #English+
convert(varchar,convert(int,100*(#Money - #Number))) +' cents'
END
RETURN (ltrim(#English))
END
--select [dbo].[fnMoneyToSpanish](2654876.36)

alternative way to TRIM for SSRS (not Crystal Reports)

I imported a report from Crystal to SSRS.
When I run the query in Microsoft Management Console, it throws errors unless I declare variables before the SELECT statement. When I run the query from Visual Studio, it bypasses these variables and only throws an error on the TRIM function.
From what I can tell a JOIN statement may be used instead of a TRIM, but I am not sure.
This is the portion of a where clause that I am trying to change/adapt to work with SSRS, which is throwing an error -- any suggestions appreciated.
Also, I am having issues with the DateSerial in the WHERE clause as follows:
AND (CAST(#StartDate AS Date) <> DateSerial(1900, 01, 01)) AND
Trim does not work in SQL only in the report expressions you would have to use LTrim and RTrim to make this work.
AND ( ( NOT ( #Status IS NULL )
AND RTrim(LTrim(#Status)) <> 'All' )
(( ( RTrim(Ltrim(#Status)) = 'Completed' )
AND RTrim(LTrim(#AssignedTo)) <> 'All' )
AND ( submission.assignedto IN ( #AssignedTo ) )
INCLUDING THE ENTIRE WHERE CLAUSE:
WHERE ( #ParameterIds IS NOT NULL or ParameterIds = #ParameterIds )
AND #ParameterIds <> 0 )
AND ( requested_table.parameterid IN ( #ParameterIds ) ) )
AND requested_table.columnname = 'INSERT'
AND ( ( NOT ( #Parameter2 IS NULL )
AND Trim(#Parameter2) <> 'All' )
AND (( ( Trim(#Parameter2) = 'Completed' )
AND (( requested_table.columnname = 'Dup'
OR requested_table.columnname = 'IDup'
OR requested_table.columnname = 'W/D'
OR requested_table.columnname = 'Done'
OR requested_table.columnname = 'QA Review Dup'
OR requested_table.columnname = 'X' ))
OR ( requested_table.columnname IN ( #Parameter2 ) ) )) )
AND ( ( #ParameterIds = 0 )
AND ( ( ( NOT ( #StartDate IS NULL )
AND ( Cast (#StartDate AS DATE) <>
Dateserial(1900, 01, 01) ) )
AND ( submission.dateimported >= Datevalue (#StartDate) ) )
AND ( ( NOT ( #EndDate IS NULL )
AND ( Cast (#EndDate AS DATE) <>
Dateserial(1900, 01, 01) )
)
AND ( table.dateimported <= Datevalue (#EndDate) )
) ) )
AND ( ( #ParameterIds = 0 )
AND (( ( NOT ( #Parameter5 IS NULL )
AND Trim(#Parameter5) <> 'All' )
AND ( table.assignedto IN ( #Parameter5 ) ) )) )
Fix the Dateserial and this should work.
WHERE ( #ParameterIds IS NOT NULL or ParameterIds = #ParameterIds )
AND (#ParameterIds <> 0 )
AND ( requested_table.parameterid IN ( #ParameterIds ) )
AND requested_table.columnname = 'INSERT'
AND ( ( (#Parameter2 IS NOT NULL )
AND LTRIM(RTrim(#Parameter2)) <> 'All' )
AND (( ( LTRIM(RTrim((#Parameter2)) = 'Completed' )
AND (( requested_table.columnname = 'Dup'
OR requested_table.columnname = 'IDup'
OR requested_table.columnname = 'W/D'
OR requested_table.columnname = 'Done'
OR requested_table.columnname = 'QA Review Dup'
OR requested_table.columnname = 'X' ))
OR ( requested_table.columnname IN ( #Parameter2 ) ) )) )
AND ( ( #ParameterIds = 0 )
AND ( ( ( ( #StartDate IS NOT NULL )
AND ( Cast (#StartDate AS DATE) <>
Dateserial(1900, 01, 01) ) )
AND ( submission.dateimported >= (#StartDate) ) )
AND ( ( ( #EndDate IS NOT NULL )
AND ( Cast (#EndDate AS DATE) <>
Dateserial(1900, 01, 01) )
)
AND ( table.dateimported <= (#EndDate) )
) ) )
AND ( ( #ParameterIds = 0 )
AND (( ( ( #Parameter5 IS NOT NULL )
AND RTRIM(LTrim(#Parameter5)) <> 'All' )
AND ( table.assignedto IN ( #Parameter5 ) ) )) )

Counting words in column

i must get count number the tag
<name></name>
in column.
<users><name>Tomek</name><name>Pawel</name><name>Krzysiek</name></users>
In this example data, queries should return 3.
Using XPath you can easily implement the logic.
Example XPath for your scenario : count(/users/name)
Result : 3
Test Here
Dynamic sql solution:
DECLARE #Table TABLE (Names NVARCHAR(1100))
INSERT INTO #Table VALUES
('<users><name>Tomek</name><name>Pawel</name><name>Krzysiek</name></users>'),
('<users><name>Tomek</name><name>Pawel</name><name>Krzysiek</name></users>'),
('<users><name>Tomek</name><name>Pawel</name><name>Krzysiek</name></users>')
DECLARE #Sql NVARCHAR(MAX)
SET #Sql = ''
SELECT
#Sql = #Sql +
REPLACE(
REPLACE(
REPLACE(
REPLACE(Names,'</name>',''' as Names UNION ALL ')
,'<name>','SELECT ''')
,'</users>','')
,'<users>','')+CHAR(10)
FROM #Table
SET #Sql = LEFT(#Sql,LEN(#Sql)-11)
SET #Sql = 'SELECT COUNT(Names) AS Names FROM (' + #Sql + ') as AllNames'
EXEC(#Sql)
if you work with xml data then try this variant
DECLARE #XMLdata XML = N'<users><name>Tomek</name><name>Pawel</name><name>Krzysiek</name></users>'
SELECT COUNT(*)
FROM #XMLdata.nodes('/users/name') col ( name )
This variant can be usefull when data storaged like a string (varchar)
--create temp table for testing
IF OBJECT_ID('Tempdb..#Tags') IS NOT NULL
DROP TABLE #Tags
CREATE TABLE #Tags
(
SampleText VARCHAR(1000)
)
INSERT INTO #Tags
( SampleText )
VALUES ( '<users><name>Tomek</name><name>Pawel</name><name>Krzysiek</name></users>' ),
( '<users><name>Somik</name><name>Pawel</name><name>Krzysiek</name></users>' ),
( '<users><name>Krolik</name><name>Pawel</name><name>Krzysiek</name></users>' ),
( '<users><name>Domik</name><name>Pawel</name><name>Krzysiek</name></users>' ),
( '<users><name>Zontik</name><name>Pawel</name><name>Krzysiek</name></users>' );
--------------------------------------------------------------------------------
-- recursive cte for split string
WITH cte
AS ( SELECT n = 1
UNION ALL
SELECT n + 1
FROM cte
WHERE n <= 1000
)
--------------------------------------------------------------------------------
-- final query
SELECT COUNT(*) AS Cnt
FROM cte
JOIN #Tags AS T ON n <= LEN(T.SampleText)
WHERE SUBSTRING(T.SampleText, n, 7) = '</name>'
OPTION ( MAXRECURSION 1000 )

TSQL Case WHEN LIKE REPLACE

Newbie question... looking for the fastest way to update a new column based on the existence of a value from another table, while replacing values.
Example, below, taking the words 'Bought a car' with 'car' into another table. The problem is 'Bought a car' is into another table.
I did a hack to reselect the value and do a replace, but with more rows, the performance is horrible, taking up to 3 to 5 minutes to perform.
Oh SQL Gurus, what is the best way to do this?
Example
DECLARE #Staging_Table TABLE
(
ACCTID INT IDENTITY(1,1),
NAME VARCHAR(50),
PURCHASES VARCHAR(255)
)
INSERT INTO #Staging_Table (Name, Purchases)
VALUES ('John','Bought a table')
INSERT INTO #Staging_Table (Name, Purchases)
VALUES ('Jack','Sold a car')
INSERT INTO #Staging_Table (Name, Purchases)
VALUES ('Mary','Returned a chair')
DECLARE #HISTORY TABLE
(
ACCTID INT IDENTITY(1,1),
NAME VARCHAR(50),
Item VARCHAR(255)
)
INSERT INTO #HISTORY (Name, Item)
VALUES ('John','')
INSERT INTO #HISTORY (Name, Item)
VALUES ('Jack','')
INSERT INTO #HISTORY (Name, Item)
VALUES ('Mary','')
UPDATE #HISTORY
Set ITEM = CASE WHEN EXISTS(
Select ts.Purchases as Output from #Staging_Table ts
where ts.NAME = Name AND ts.PURCHASES LIKE '%table%')
THEN REPLACE((Select ts2.PURCHASES Output
from #Staging_Table ts2 where ts2.NAME = Name AND ts2.PURCHASES LIKE '%table%'),'Bought a ','')
WHEN EXISTS(
Select ts.Purchases as Output from #Staging_Table ts
where ts.NAME = Name AND ts.PURCHASES LIKE '%car%')
THEN REPLACE((Select ts2.PURCHASES Output
from #Staging_Table ts2 where ts2.NAME = Name AND ts2.PURCHASES LIKE '%car%'),'Bought a ','')
End
SELECT * FROM #HISTORY
DECLARE #Staging_Table TABLE
(
ACCTID INT IDENTITY(1, 1) ,
NAME VARCHAR(50) ,
PURCHASES VARCHAR(255)
)
INSERT INTO #Staging_Table
( Name, Purchases )
VALUES ( 'John', 'Bought a table' ),
( 'Jack', 'Sold a car' ),
( 'Mary', 'Returned a chair' )
DECLARE #HISTORY TABLE
(
ACCTID INT IDENTITY(1, 1) ,
NAME VARCHAR(50) ,
Item VARCHAR(255)
)
INSERT INTO #HISTORY
( Name, Item )
VALUES ( 'John', '' ),
( 'Jack', '' ),
( 'Mary', '' )
UPDATE L
SET L.ITEM = ( CASE WHEN R.PURCHASES LIKE '%table%'
THEN REPLACE(R.PURCHASES, 'Bought a ', '')
WHEN R.PURCHASES LIKE '%car%'
THEN REPLACE(R.PURCHASES, 'Sold a ', '')
END )
FROM #HISTORY AS L
JOIN #Staging_Table AS R ON L.NAME = R.NAME
WHERE ( R.PURCHASES LIKE '%table%'
OR R.PURCHASES LIKE '%car%'
)
SELECT *
FROM #HISTORY