Split snowflake db string based on a delimiter - snowflake-cloud-data-platform

got a string
AccountID, ÿþ 23.04.2019 ÿþ ÿþ AccountNum, ÿþ 68 ÿþ ÿþ ActiveDate, ÿþ Jan 1 1900 12:00AM ÿþ ÿþ BankAccount, ÿþ ÿþ ÿþ BankAccountType, ÿþ 0 ÿþ 1 ÿþ BankCIN, ÿþ ÿþ ÿþ BankCodeType, ÿþ 0 ÿþ 0 ÿþ BankConstantSymbol, ÿþ 0 ÿþ ÿþ BankContractAccount, ÿþ ÿþ ÿþ BankGroupID, ÿþ ÿþ ÿþ BankIBAN, ÿþ ÿþ ÿþ CellularPhone, ÿþ 123 ÿþ 321 ÿþ ContactPerson
text format is
[ColumnName], ÿþ [OldValue] ÿþ [NewValue] ÿþ
Required result is
Thanks for any pointers!
Tried replacing the delimiter with split_to_table, tried split_part...keep getting stuck on the time from activedate. Then I assumed since I could split_to_table I'll use LAG or LEAD to get the following index value as a column...but got stuck.

This seems to work:
WITH SPLIT_DATA AS (
SELECT
-- Each group of 3 values will form the same row
ceil(index/3) ROW_ID
-- label each element as to which column in each row it should be assigned to
, case when mod(index,3) = 0 then 3 else mod(index,3) end pos
-- Remove the trailing comma from the column name values
, CASE WHEN RIGHT(TRIM(VALUE),1) = ',' THEN LEFT(TRIM(VALUE),LENGTH(TRIM(VALUE))-1) ELSE TRIM(VALUE) END VALUE
FROM COMPLEX_SPLIT, LATERAL SPLIT_TO_TABLE(LONG_STRING,'ÿþ ')
),
PIVOT_DATA AS (
SELECT *
FROM SPLIT_DATA
PIVOT(MIN(VALUE) FOR POS IN (1, 2, 3))
AS p (ROW_ID, COLUMN_NAME, OLD_VALUE, NEW_VALUE)
)
SELECT COLUMN_NAME, OLD_VALUE, NEW_VALUE
FROM PIVOT_DATA
ORDER BY COLUMN_NAME
;

Related

Calculating Inventory running quantity/value & moving average unit cost

Any help to the following problem I have will be appreciated, thank you.
I am trying to perform some retrospective costings on stock inventory and failing to realise my results… I have tried various window functions (lead/Lag/row_number) etc along with multiple ctes and also First_Value….but have failed miserably….so hopefully your thoughts may get me where I want to be.
MS SQL SERVER 2019
This is what I have:
tId
tType
tcode
tDate
tQty
tValue
1
PO_IN
456
20210901
200
3654.00
2
SO_OUT
456
20210903
-155
3
SO_OUT
456
20210904
-15
4
PO_IN
456
20210905
150
3257.00
5
SO_OUT
456
20210906
-120
6
SO_OUT
456
20210907
-10
7
FIN_ADJ
456
20210908
0
-75.00
8
SO_OUT
456
20210909
-20
9
PO_IN
456
20210902
5
0.00
10
SO_OUT
456
20210910
-35
This is what I wish to achieve:
tId
tType
tcode
tDate
tQty
tValue
Run_Qty
Run_Value
avg_cost
1
PO_IN
456
20210901
200
3654.00
200
3654.00
18.27
2
SO_OUT
456
20210903
-155
45
822.15
18.27
3
SO_OUT
456
20210904
-15
30
548.10
18.27
4
PO_IN
456
20210905
150
3257.00
180
3805.10
21.14
5
SO_OUT
456
20210906
-120
60
1268.37
21.14
6
SO_OUT
456
20210907
-10
50
1056.97
21.14
7
FIN_ADJ
456
20210908
0
-75.00
50
981.97
19.64
8
SO_OUT
456
20210909
-20
30
589.18
19.64
9
PO_IN
456
20210902
5
0.00
35
589.18
16.83
10
SO_OUT
456
20210910
-35
0
0.00
PO_IN have a positive tqty and a positive or zero tvalue. This can be used to create/ adjust the moving avg cost per unit.
SO-OUT are negative tqty and have NULL tValue and decrement the running qty column and decrement the running value column by the tqty * the previous row avg cost
FIN_ADJ are tValue only and can be positive/negative.
the order of processing required is by tid and not tDate.
If I can get this to output the correct closing qty/value and the correct avg cost per row, I can then move onto the next step of analysis.
Thanks
EDIT....real world tables will have 100K+ rows
Some initial setup code
CREATE TABLE tst_Inv(
tId INT NOT NULL
,tType VARCHAR(7) NOT NULL
,tcode INT NOT NULL
,tDate DATE NOT NULL
,tQty INTEGER NOT NULL
,tValue NUMERIC(7,2)
);
INSERT INTO tst_Inv(tId,tType,tcode,tDate,tQty,tValue) VALUES
(1,'PO_IN',456,'20210901',200,3654.00),(2,'SO_OUT',456,'20210903',-155,NULL),(3,'SO_OUT',456,'20210904',-15,NULL)
,(4,'PO_IN',456,'20210905',150,3257.00),(5,'SO_OUT',456,'20210906',-120,NULL),(6,'SO_OUT',456,'20210907',-10,NULL)
,(7,'FIN_ADJ',456,'20210908',0,-75.00),(8,'SO_OUT',456,'20210909',-20,NULL),(9,'PO_IN',456,'20210902',5,0.00)
,(10,'SO_OUT',456,'20210910',-35,NULL);
SELECT * FROM tst_Inv
I'm using CTE
;WITH xQ
AS
(
SELECT tId,tType, tcode, tDate, tQty, tValue ,
tQty AS Run_Qty,
CAST (tValue AS NUMERIC(7,2)) AS Run_Value ,
tValue / tQty AS Avg_Cost
FROM tst_Inv
WHERE tId = 1
UNION ALL
SELECT tId,tType, tcode, tDate, tQty, tValue ,
xB.Run_Qty,
xB.Run_Value,
CASE WHEN xB.Run_Qty = 0 THEN NULL ELSE xB.Run_Value / xB.Run_Qty END AS Avg_Cost
FROM
(
SELECT tId,tType, tcode, tDate, tQty, tValue,
Run_Qty,
CAST(
CASE xA.tType
WHEN 'PO_IN' THEN xA.tValue + xA.Run_Value
WHEN 'FIN_ADJ' THEN xA.tValue + xA.Run_Value
ELSE xA.Run_Qty * xA.Avg_Cost
END
AS NUMERIC(7,2)) AS Run_Value,
xA.Avg_Cost
FROM
(
SELECT tst_Inv.* ,
tst_Inv.tQty + xQ.Run_Qty AS Run_Qty,
xQ.Run_Value,
xQ.Avg_Cost
FROM tst_Inv
INNER JOIN xQ ON (tst_Inv.tId -1) = xQ.tId
) AS xA
) AS xB
)
SELECT * FROM xQ

SQL extracting specific values from a Varchar column & Splitting those column values into rows

I have tried executing the below code & it throws error
Msg 2809,
The request for procedure 'SplitStringTest' failed because 'SplitStringTest' is a table valued function object."
DECLARE #ID INT
DECLARE #Name VARCHAR(MAX)
DECLARE #opt VARCHAR(MAX)
DECLARE CursorTest CURSOR
FOR SELECT ID,
Name,
dbo.RemoveCharacterswithoutspacesTest(Desc) as opt
FROM input_table
OPEN CursorTest
FETCH NEXT FROM CursorTest
INTO #ID,#Name, #opt
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC SplitStringTest #opt
FETCH NEXT FROM CursorTest
INTO #ID, #Name, #opt
END
CLOSE CursorTest
DEALLOCATE CursorTest
I am looking for a solution in SQL Server as shown below
Current table:
ID Name Desc
-----------------------
123 KR difference 76887 ghfr 88888063 7282
456 CD 088724 see there 29851 bus 0012
expected output:
ID NAME DESC
-----------------------
123 KR 76887
123 KR 88888063
123 KR 7282
456 CD 088724
456 CD 29851
456 CD 0012
As you tagged it with PL/SQL tag, which belongs to Oracle, here's one option:
SQL> with test (id, name, descr) as
2 (select 123, 'KR', 'difference 76887 ghfr 88888063 7282' from dual union
3 select 456, 'CD', '088724 see there 29851 bus 0012' from dual
4 )
5 select id, name,
6 regexp_substr(descr, '\d+', 1, column_value) descr
7 from test,
8 table(cast(multiset(select level from dual
9 connect by level <= regexp_count(descr, ' ') + 1
10 ) as sys.odcinumberlist))
11 where regexp_like(regexp_substr(descr, '\d+', 1, column_value), '\d+')
12 order by id, name;
ID NAME DESCR
---------- ---------- ----------
123 KR 76887
123 KR 88888063
123 KR 7282
456 CD 088724
456 CD 29851
456 CD 0012
6 rows selected.
SQL>
SQL Server (starting with 2016)
SELECT ID, Name, value
FROM Table1
CROSS APPLY STRING_SPLIT([desc], ' ')
WHERE ISNUMERIC(value)=1;
Output
ID Name value
123 KR 76887
123 KR 88888063
123 KR 7282
456 CD 088724
456 CD 29851
456 CD 0012
Live Demo
http://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=f049720899f7a106c83ae7c02bfbde32

T-SQL Count of Records in Status for Previous Months

I have a T-SQL Quotes table and need to be able to count how many quotes were in an open status during past months.
The dates I have to work with are an 'Add_Date' timestamp and an 'Update_Date' timestamp. Once a quote is put into a 'Won' or 'Loss' columns with a value of '1' in that column it can no longer be updated. Therefore, the 'Update_Date' effectively becomes the Closed_Status timestamp.
Here's a few example records:
Quote_No Add_Date Update_Date Open_Quote Win Loss
001 01-01-2016 NULL 1 0 0
002 01-01-2016 3-1-2016 0 1 0
003 01-01-2016 4-1-2016 0 0 1
Here's a link to all the data here:
https://drive.google.com/open?id=0B4xdnV0LFZI1T3IxQ2ZKRDhNd1k
I asked this question previously this year and have been using the following code:
with n as (
select row_number() over (order by (select null)) - 1 as n
from master..spt_values
)
select format(dateadd(month, n.n, q.add_date), 'yyyy-MM') as yyyymm,
count(*) as Open_Quote_Count
from quotes q join
n
on (closed_status = 1 and dateadd(month, n.n, q.add_date) <= q.update_date) or
(closed_status = 0 and dateadd(month, n.n, q.add_date) <= getdate())
group by format(dateadd(month, n.n, q.add_date), 'yyyy-MM')
order by yyyymm;
The problem is this code is returning a cumulative value. So January was fine, but then Feb is really Jan + Feb, and March is Jan+Feb+March, etc. etc. It took me a while to discover this and the numbers returned now way, way off and I'm trying to correct them.
From the full data set the results of this code are:
Year-Month Open_Quote_Count
2017-01 153
2017-02 265
2017-03 375
2017-04 446
2017-05 496
2017-06 560
2017-07 609
The desired result would be how many quotes were in an open status during that particular month, not the cumulative :
Year-Month Open_Quote_Count
2017-01 153
2017-02 112
2017-03 110
2017-04 71
Thank you in advance for your help!
Unless I am missing something, LAG() would be a good fit here
Example
Declare #YourTable Table ([Year-Month] varchar(50),[Open_Quote_Count] int)
Insert Into #YourTable Values
('2017-01',153)
,('2017-02',265)
,('2017-03',375)
,('2017-04',446)
,('2017-05',496)
,('2017-06',560)
,('2017-07',609)
Select *
,NewValue = [Open_Quote_Count] - lag([Open_Quote_Count],1,0) over (Order by [Year-Month])
From #YourTable --<< Replace with your initial query
Returns
Year-Month Open_Quote_Count NewValue
2017-01 153 153
2017-02 265 112
2017-03 375 110
2017-04 446 71
2017-05 496 50
2017-06 560 64
2017-07 609 49

How to use ORDER BY in SQL Server on a column of a table?

We have a table like this:
bok jel str1 str2
1 3 184 185
1 3 215 219
1 3 229 244
1 3 267 273
1 3 331 331
1 3 338 339
we want sort by str1 and str2.
SELECT *
FROM YourTable
ORDER BY str1,
str2
General practice is:
SELECT *
FROM TEMP
ORDER BY
STR1
, STR2
Another possibility is ordering by STR1 + STR2 but be aware that it will return different results . e.g on SQLFiddle
Set NOCOUNT ON
select bok, jel, st1, st2 from YourTable order by str1, str2

query from two table with multiple conditions [duplicate]

This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
joining two table with different conditions of different column
tbl_User
ID mobileno dateofregistration registrationstate
44 1674174925 2011-04-18 10:17:30.670 0
45 1677864168 2011-03-31 10:20:22.450 1
46 1677864161 2011-04-18 20:47:35.293 0
47 1674174925 2011-03-29 09:28:55.200 1
48 1674174967 2011-03-29 09:28:55.100 1
Tbl_cdr
slno ano startTime
0 1677864161 2011-03-29 14:37:35.000
0 1677864161 2011-03-29 15:36:47.000
0 1677864165 2011-03-31 15:07:00.000
0 1677864166 2011-03-31 15:04:13.000
0 1677864167 2011-03-29 14:36:17.000
0 1677864167 2011-03-31 15:04:46.000
0 1677864168 2011-03-31 15:00:07.000
0 1677864168 2011-03-31 15:01:39.000
0 1677864168 2011-03-31 15:07:44.000
0 1677864168 2011-03-31 15:08:14.000
Output
Date ActFail NewAct RenFail SuccessRen
29/03/2011 1 2 0 0
31/03/2011 3 1 0 0
Conditions
1.Date : group by startTime ;
2. ActFail : Count(*) From Tbl_cdr with condition ano!=mobileno.`
3.NewAct : `count (*) from Tbl_user with condition registrationstate=1`
4.RenFail : `count * from Tbl_cdr with condition (ano=mobileno and registrationstate=0)`
5.SuccessRate : Count(*) from tbl_user when only registratonstate changed from 0 to 1
All query will be groupby Tbl_cdr.startTime and between user given timelimit.
i,hv tried with this,but in vain
select
Convert(varchar(10), startTime,103) as Date,
count(*) As ActivationFail,
(Select COUNT(*) from tbl_User where registrationstate='1') as NewActivation
from Tbl_cdr c
left join Tbl_User u on c.ano = u.mobileno
where u.id is null and startTime between #date1 and #date2
group by Convert(varchar(10),startTime,103)
any help,Plz.. is it possible to show all the 5 column in a single table with the above conditions???
you have not explain what exactly what you need to do, but i can give some advise.
remove all the convert and count, and try selecting first. you can use subqueries to make your work eaiser.

Resources