Flat File to SQL server - sql-server

I want to read data from a TXT/FLAT file and arrange the data using the first column contents as column names and the data after the semi colon as records .
SAMPLE DATA
{1:F01SBZAZAJJXXXX9999999999}{2:I940SBICMWMXXXXXN}{4:
:20:D424A100110011E4
:25:020083203
:28C:49/1
:60F:C140106ZAR1029873,62
:61:1401060106DR5000,NTRF99999999//NONREF20140106-13175-016050001844421
:86:/PREF/ZA000520CATS THIRD PARTY PAYMENT
:62F:C140106ZAR0,00
-}
{1:F01SBZAZAJJXXXX9999999999}{2:I940SBICMWMXXXXXN}{4:
:20:D3DE7040110011E4
:25:020083204
:28C:51/1
:60F:C140106NAD1030073,
:61:1401060106DR5000,NTRF20140106-13175-0//NONREF20140106-13175-016050001844421
:86:/PREF/NA000520TRANSFER
:62F:C140106NAD0,00
-}
The query below only worked for one chunk...I need a query that reads the whole data set and arranges it as shown above in the attached image.
SELECT [20], [25], [28C], [60F], [61], [86], [62F]
FROM
(SELECT column2, column3 FROM [dbo].[Sample MT940]) AS Source_Table
PIVOT
(MAX(column3)
FOR
column2 in ([20], [25], [28C], [60F], [61], [86], [62F])
) AS PIVOT_TABLE
Expected Results

Please try the following solution.
The assumption is that you always have full set of values for each row in the target table: ([20], [25], [28C], [60F], [61], [86], [62F])
We are grouping all rows into buckets with 9 consecutive rows in each of them via NTILE() function.
SQL
-- DDL and sample data population, start
DECLARE #tbl TABLE (Token VARCHAR(1024));
INSERT #tbl (Token) VALUES
('{1:F01SBZAZAJJXXXX9999999999}{2:I940SBICMWMXXXXXN}{4:'),
(':20:D424A100110011E4'),
(':25:020083203'),
(':28C:49/1'),
(':60F:C140106ZAR1029873,62'),
(':61:1401060106DR5000,NTRF99999999//NONREF20140106-13175-016050001844421'),
(':86:/PREF/ZA000520CATS THIRD PARTY PAYMENT'),
(':62F:C140106ZAR0,00'),
('-}'),
('{1:F01SBZAZAJJXXXX9999999999}{2:I940SBICMWMXXXXXN}{4:'),
(':20:D3DE7040110011E4'),
(':25:020083204'),
(':28C:51/1'),
(':60F:C140106NAD1030073,'),
(':61:1401060106DR5000,NTRF20140106-13175-0//NONREF20140106-13175-016050001844421'),
(':86:/PREF/NA000520TRANSFER'),
(':62F:C140106NAD0,00'),
('-}');
-- DDL and sample data population, end
DECLARE #group INT = (SELECT COUNT(*) FROM #tbl) / 9
;WITH rs AS
(
SELECT *
, _token = PARSENAME(REPLACE(token,':','.'),1)
, seq = (ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) % 9
, grp = NTILE(#group) OVER (ORDER BY (SELECT NULL))
FROM #tbl
)
SELECT DISTINCT [20] = MAX(IIF(seq = 2, _token, '')) OVER (PARTITION BY grp)
, [25] = MAX(IIF(seq = 3, _token, '')) OVER (PARTITION BY grp)
, [28C] = MAX(IIF(seq = 4, _token, '')) OVER (PARTITION BY grp)
, [60F] = MAX(IIF(seq = 5, _token, '')) OVER (PARTITION BY grp)
, [61] = MAX(IIF(seq = 6, _token, '')) OVER (PARTITION BY grp)
, [86] = MAX(IIF(seq = 7, _token, '')) OVER (PARTITION BY grp)
, [62F] = MAX(IIF(seq = 8, _token, '')) OVER (PARTITION BY grp)
FROM rs;
Output
20
25
28C
60F
61
86
62F
D3DE7040110011E4
020083204
51/1
C140106NAD1030073,
1401060106DR5000,NTRF20140106-13175-0//NONREF20140106-13175-016050001844421
/PREF/NA000520TRANSFER
C140106NAD0,00
D424A100110011E4
020083203
49/1
C140106ZAR1029873,62
1401060106DR5000,NTRF99999999//NONREF20140106-13175-016050001844421
/PREF/ZA000520CATS THIRD PARTY PAYMENT
C140106ZAR0,00

Related

Multi - Columns OVERLAPPING DATES

;with cte as (
select Domain_Id, Starting_Date, End_Date
from Que_Date
union all
select t.Domain_Id, cte.Starting_Date, t.End_Date
from cte
join Que_Date t on cte.Domain_Id = t.Domain_Id and cte.End_Date = t.Starting_Date),
cte2 as (
select *, rn = row_number() over (partition by Domain_Id, End_Date order by Domain_Id)
from cte
)
select DISTINCT Domain_Id, Starting_Date, max(End_Date) enddate
from cte2
where rn=1
group by Domain_Id, Starting_Date
order by Domain_Id, Starting_Date;
select * from Que_Date
This is the code that I have wrote but i am getting an extra row i.e 2nd row is extra, the expected output should have only 1st, 3rd and 4th row as output so please help me with it.
I have attached an image showing Input, Excepted Output, and the output that I am getting.
You've got so many results in your first cte. Your first cte has consisting domains. So you cannot filter domains based on your cte. So you query has unnecessary rows.
Try this solution. Cte ConsistentDomains has just consistent domains. So based on this cte, we can get not overlapped results.
Create and fill data:
CREATE TABLE FooTable
(
Domain_ID INT,
Starting_Date DATE,
End_Date Date
)
INSERT INTO dbo.FooTable
(
Domain_ID,
Starting_Date,
End_Date
)
VALUES
( 1, -- Domain_ID - int
CONVERT(datetime,'01-01-2011',103), -- Starting_Date - date
CONVERT(datetime,'05-01-2011',103) -- End_Date - date
)
, (1, CONVERT(datetime,'05-01-2011',103), CONVERT(datetime,'07-01-2011',103))
, (1, CONVERT(datetime,'07-01-2011',103), CONVERT(datetime,'15-01-2011',103))
, (2, CONVERT(datetime,'11-05-2011',103), CONVERT(datetime,'12-05-2011',103))
, (2, CONVERT(datetime,'13-05-2011',103), CONVERT(datetime,'14-05-2011',103))
Query to find not overlapping results:
DECLARE #startDate varchar(50) = '2011-01-01';
WITH ConsistentDomains AS
(
SELECT
f.Domain_ID
, f.Starting_Date
, f.End_Date
FROM FooTable f
WHERE f.Starting_Date = #startDate
UNION ALL
SELECT
s.Domain_ID
, s.Starting_Date
, s.End_Date
FROM FooTable s
INNER JOIN ConsistentDomains cd
ON s.Domain_ID = cd.Domain_ID
AND s.Starting_Date = cd.End_Date
), ConsistentDomainsRownumber AS
(
SELECT
cd.Domain_ID
, cd.Starting_Date
, cd.End_Date
, ROW_NUMBER() OVER (PARTITION BY cd.Domain_ID ORDER BY cd.Starting_Date,
cd.End_Date) RN
FROM ConsistentDomains cd
)
SELECT cd.Domain_ID
, convert(varchar, cd.Starting_Date, 105) Starting_Date
, convert(varchar, cd.End_Date, 105) End_Date
FROM ConsistentDomainsRownumber cd WHERE cd.RN = 1
UNION ALL
SELECT
ft.Domain_ID
, convert(varchar, ft.Starting_Date, 105) Starting_Date
, convert(varchar, ft.End_Date, 105) End_Date
FROM dbo.FooTable ft WHERE ft.Domain_ID NOT IN (SELECT cd.Domain_ID FROM
ConsistentDomainsRownumber cd)
Output:
I used the same table creating script as provided by #stepup, but you can also get your outcome in this way.
CREATE TABLE testtbl
(
Domain_ID INT,
Starting_Date DATE,
End_Date Date
)
INSERT INTO testtbl
VALUES
(1, convert(date, '01-01-2011' ,103), convert(date, '05-01-2011',103) )
,(1, convert(date, '05-01-2011' ,103), convert(date, '07-01-2011',103) )
,(1, convert(date, '07-01-2011' ,103), convert(date, '15-01-2011',103) )
,(2, convert(date, '11-05-2011' ,103), convert(date, '12-05-2011',103) )
,(2, convert(date, '13-05-2011' ,103), convert(date, '14-05-2011',103) )
You can make use of self join and Firs_value and last value within the group to make sure that you are comparing within the same ID and overlapping dates.
select distinct t.Domain_ID,
case when lag(t1.starting_date)over (partition by t.Domain_id order by
t.starting_date) is not null
then first_value(t.Starting_Date) over (partition by t.domain_id order by
t.starting_date)
else t.Starting_Date end StartingDate,
case when lead(t.domain_id) over (partition by t.domain_id order by t.starting_date) =
t1.Domain_ID then isnull(last_value(t.End_Date) over (partition by t.domain_id order by t.end_date rows between unbounded preceding and unbounded following),t.End_Date)
else t.End_Date end end_date
from testtbl t
left join testtbl t1 on t.Domain_ID = t1.Domain_ID
and t.End_Date = t1.Starting_Date
and t.Starting_Date < t1.Starting_Date
Output:
Domain_ID StartingDate end_date
1 2011-01-01 2011-01-15
2 2011-05-11 2011-05-12
2 2011-05-13 2011-05-14

SQL Server sum query every 06:30 AM

Really need some help: I have a SQL Server table like this :
And I want to do a query to count value everyday start from 06:30 today until 06:29 tomorrow.
The problem is, the value does not start from 0 every 06:30.
I need query like this: Select maximum value per code first, ex :
(code : value)
M12 : 108,
M77 : 26
then the M77 value not start from 06:30.
I need to do : 26 - 12 (value before 06:30:00), so the M77 now is 14.
Finally sum the M77 and M12 = 14 + 108 = 122.
My expected output only for total value per date.
Based on my DB (image), the total value will be 26 - 12 =14.
26 is the latest value.
12 is value before 06:30
How to do it in SQL Server? Please help me
if i do understand you requirement correctly.
The query explanation are in code comments
; with
-- for getting the max value by code, rn = 1 is the max value
cte1 as
(
select *, rn = row_number() over (partition by code order by value desc)
from sample_table
),
-- for getting rows before 6:30, rn = 1 is the last record before 6:30
cte2 as
(
select *, rn = row_number() over (partition by code order by [date] desc)
from sample_table
where convert(time, [date]) < '06:30'
)
select total = sum(case when convert(time, c1.[date]) < '06:30'
then c1.value
else c1.value - c2.value
end)
from cte1 c1
left join cte2 c2 on c1.code = c2.code
and c1.rn = c2.rn
where c1.rn = 1
Try this
SELECT SUM([output]) AS [output]
FROM (
SELECT [latest]
,[before]
,(CASE WHEN [latest] = [before] THEN [latest]
ELSE [latest] - [before] END) AS [output]
FROM (
SELECT [code]
,MAX([value]) AS [latest]
,(SELECT MAX([value])
FROM [table]
WHERE [date] &lt CONVERT(datetime, CONVERT(varchar(10), CONVERT(date, [date])) + ' 06:30:00:000')
AND [code] = [t].[code]
GROUP BY [code]) AS [before]
FROM [table] AS [t]
GROUP BY [code]) AS [src]
) AS [rpt]
Try this puzzle:
CREATE TABLE TestTable
(
[date] datetime,
value int,
code varchar(10)
)
GO
INSERT INTO [dbo].[TestTable]
([date]
,[value]
,[code])
VALUES
('2018-09-13 06:20:52.803'
,100
,'M12'),
('2018-09-13 06:21:52.803'
,102
,'M12')
, ('2018-09-13 06:22:52.803'
,104
,'M12')
, ('2018-09-13 06:23:52.803'
,106
,'M12')
, ('2018-09-13 06:24:52.803'
,108
,'M12')
, ('2018-09-13 06:25:52.803'
,2
,'M77')
, ('2018-09-13 06:29:14.803'
,4
,'M77')
, ('2018-09-13 06:29:16.803'
,6
,'M77')
, ('2018-09-13 06:29:18.803'
,8
,'M77')
, ('2018-09-13 06:29:45.803'
,10
,'M77')
, ('2018-09-13 06:29:55.803'
,12
,'M77')
, ('2018-09-13 06:30:18.803'
,14
,'M77')
, ('2018-09-13 06:31:18.803'
,26
,'M77')
;WITH RESULT AS (
SELECT
TT.code
, MaxValueThatday = max(maxval.MAXVALUE )
, MaxValueBefore630NextDay = max(MAXValBefore630.MAXVALUE)
, ResultSubstraction =
CASE WHEN max(maxval.MAXVALUE ) <> max(MAXValBefore630.MAXVALUE)
THEN max(maxval.MAXVALUE ) - max(MAXValBefore630.MAXVALUE)
ELSE max(maxval.MAXVALUE )
END
FROM [dbo].[TestTable] TT
OUTER APPLY(
SELECT max(VALUE) MAXVALUE
, code
FROM [dbo].[TestTable] aa
WHERE Aa.code = tt.code
group by code
)maxval
OUTER APPLY(
SELECT max(A.VALUE) MAXVALUE
, code
FROM [dbo].[TestTable] A
WHERE DATEPART(HOUR,[DATE]) <= 6 AND DATEPART(MINUTE,[DATE]) < 30
and A.code = tt.code
group by code
)MAXValBefore630
where ( [DATE] > DATEADD(MINUTE,390,CAST({ fn CURDATE()} AS DATETIME) ) ) --6:30 today
group by tt.code
)
SELECT SUM(ResultSubstraction)
FROM RESULT

Ordering events and retaining earliest and latest timestamp at each location in sequence

I have some data which records some sequential processing events.
Each event occurs at a location (Location) and includes both a begin date (BeginDT) and an end date (EndDT).
Processing at a Location may involve multiple sequential steps each of which is recorded with a BeginDT and EndDT.
A step which is non-final at a location should be recorded as complete (Complete as true (1)).
A step which is final at a location should be recorded with incomplete (Complete as false (0)).
However, it is possible for processing at a location to be incomplete due to some missing or erroneous records.
When processing at a location has a step (or steps) which indicate(s) incomplete but no subsequent final step to indicate complete then the incomplete record (or most recent incomplete record of the sequence at the location) is to be considered the final record.
Processing multiple times at the same location in sequence may occur.
When processing multiple times at the same location in sequence and the leading event at the location is complete then each event is to be considered an entirely separate.
I have included a method which I was trying to use to help determine how each event is to be handled by identifying the previous and next records but I am not sure if that is a useful approach.
The desired final result is the Order, Location, earliest BeginDT, and latest EndDT for each sequential set of processing events at a Location:
/*
[Order] Location BeginDT EndDT
1 A 2000-01-01 2000-01-06
2 B 2000-01-10 2000-01-11
3 C 2000-01-20 2000-01-21
4 D 2000-01-30 2000-01-31
5 A 2000-02-01 2000-02-02
6 C 2000-02-10 2000-02-11
7 C 2000-02-20 2000-02-21
8 B 2000-03-01 2000-03-02
9 D 2000-03-10 2000-03-11
10 D 2000-03-20 2000-03-23
11 E 2000-03-30 2000-03-31
*/
declare #T table (
ID int identity,
Location varchar(20),
Complete bit,
BeginDT date,
EndDT date
);
insert #T (Location, Complete, BeginDT, EndDT)
values
('A', 0, '2000-01-01', '2000-01-02'),
('A', 0, '2000-01-03', '2000-01-04'),
('A', 1, '2000-01-05', '2000-01-06'),
('B', 1, '2000-01-10', '2000-01-11'),
('C', 1, '2000-01-20', '2000-01-21'),
('D', 0, '2000-01-30', '2000-01-31'),
('A', 1, '2000-02-01', '2000-02-02'),
('C', 1, '2000-02-10', '2000-02-11'),
('C', 1, '2000-02-20', '2000-02-21'),
('B', 1, '2000-03-01', '2000-03-02'),
('D', 1, '2000-03-10', '2000-03-11'),
('D', 0, '2000-03-20', '2000-03-21'),
('D', 1, '2000-03-22', '2000-03-23'),
('E', 1, '2000-03-30', '2000-03-31');
with cte as (
select
row_number() over (order by BeginDT) as [Order],
Location,
Complete,
BeginDT,
EndDT
from #T
)
select
*
from cte
order by
[Order],
Complete;
with cte as (
select
row_number() over (order by BeginDT) as [Order],
Location,
Complete,
BeginDT,
EndDT
from #T
)
select
[Order],
Location,
BeginDT,
EndDT,
Complete,
max(Previous) as Previous,
max(cast(PreviousComplete as int)) as PreviousComplete,
max([Next]) as [Next]
from (
select
cte.[Order],
cte.Location,
cte.BeginDT,
cte.EndDT,
cte.Complete,
case
when cte.[Order] = j.[Order] + 1
then j.Location
else NULL
end as Previous,
case
when cte.[Order] = j.[Order] + 1
then j.Complete
else NULL
end as PreviousComplete,
case
when cte.[Order] = j.[Order] - 1
then j.Location
else NULL
end as [Next]
from cte
cross join (
select
[Order],
Location,
Complete
from cte
) as j
) as S
group by
[Order],
Location,
BeginDT,
EndDT,
Complete;
I developed a solution:
with
cte1 as (
select
row_number() over (order by BeginDT, EndDT) as [Order],
Location,
IsComplete,
BeginDT,
EndDT
from #T
),
cte2 as (
select
[Order],
Location,
case
when 1 <> 1
or Location <> Previous
or Previous is NULL
or (
1 = 1
and Location = Previous
and PreviousIsComplete = 1
)
then BeginDT
end as BeginDT,
case
when 1 <> 1
or IsComplete = 1
or (
IsComplete = 0
and (
1 <> 1
or Location <> [Next]
or [Next] is NULL
)
)
then EndDT
end as EndDT
from (
select
[Order],
Location,
BeginDT,
EndDT,
IsComplete,
max(Previous) as Previous,
max(cast(PreviousIsComplete as int)) as PreviousIsComplete,
max([Next]) as [Next]
from (
select
cte1.[Order],
cte1.Location,
cte1.BeginDT,
cte1.EndDT,
cte1.IsComplete,
case
when cte1.[Order] = cj1.[Order] + 1
then cj1.Location
else NULL
end as Previous,
case
when cte1.[Order] = cj1.[Order] + 1
then cj1.IsComplete
else NULL
end as PreviousIsComplete,
case
when cte1.[Order] = cj1.[Order] - 1
then cj1.Location
else NULL
end as [Next]
from cte1
cross join (
select
[Order],
Location,
IsComplete
from cte1
) as cj1
) as T1
group by
[Order],
Location,
BeginDT,
EndDT,
IsComplete
) as T2
),
cte3 as (
select
'Begin' as [Type],
row_number() over (order by [Order]) as [Order],
Location,
min(BeginDT) as DT
from cte2
where BeginDT is not NULL
group by
[Order],
Location
union
select
'End' as [Type],
row_number() over (order by [Order]) as [Order],
Location,
min(EndDT) as DT
from cte2
where EndDT is not NULL
group by
[Order],
Location
)
select
[Order],
Location,
[Begin] as BeginDT,
[End] as EndDT
from (
select
[Type],
[Order],
Location,
DT
from cte3
) as T
pivot (
max(DT) for [Type] in ([Begin], [End])
) as pT
order by [Order];
I welcome any improvements. Thanks.

Write a query for this table

Imagine that i have a table like below,i want to write a query that give me below result,is it possible?
Result:
100 , 2015-01-01 , ABC , XYZ
You can use PIVOT.
Query
select userid,
[date],
[job],
[address]
from
(
select userid,name,[value] from tblName
)
as s
pivot
(
max([value]) for [name] in ([date], [job], [address])
) as p;
SQL Fiddle
OR
Query
select userid,
max(case when name = 'date' then [value] else null end) as [date],
max(case when name = 'job' then [value] else null end) as job,
max(case when name = 'address' then [value] else null end) as address
from tblName
group by userid;
SQL Fiddle
Another way,
try using Group_Concatenate and Common Table Expression
;with cte as
(select userid,
STUFF((
SELECT ',' + md.[value]
FROM tblName md
WHERE m.userid = md.userid
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
as result
from tblName m group by m.userid
)
select (cast(userid as varchar(50))+','+result) as res from cte
see Demo Here

How to generate sequence numbers for hierarchical data in sql server

I have create a function in sql to get a serial number in hierarchy.I have table called Goals.the structure of table is below
GoalId ParentId Goalstatement
---------- ---------- ----------
1 0 abc
2 0 def
3 1 acc
4 2 efc
5 3 dec
6 0 efc
7 3 jhg
I want to write a function to get the result as
Serial no GoalId ParentId GoalStatement
---------- ---------- ---------- --------------------
1 1 0
2 2 0
3 6 0
1.1 3 1
1.1.1 5 3
1.1.2 7 3
2.1 4 2
----------
I have tried with common table expression
WITH Hierarchy(GoalID, ParentId, Parents)
AS
(
SELECT GoalID, GoalParentID, CAST('' AS VARCHAR(MAX))
FROM Goals AS FirtGeneration
WHERE GoalParentID =0
UNION ALL
SELECT NextGeneration.GoalID, NextGeneration.GoalParentID,
CAST(CASE WHEN Parent.Parents = ''
THEN(CAST(NextGeneration.GoalParentID AS VARCHAR(MAX)))
ELSE(Parent.Parents + '.' + CAST(NextGeneration.GoalParentID AS VARCHAR(MAX)))
END AS VARCHAR(MAX))
FROM Goals AS NextGeneration
INNER JOIN Hierarchy AS Parent ON NextGeneration.GoalParentID = Parent.GoalID
)
SELECT *
FROM Hierarchy
OPTION(MAXRECURSION 32767)
Can any one help me to write a function to create serial number in a hierarchical way
Your recursive CTE is quite close but you need to add in a ROW_NUMBER() in order to generate the sequential numbers at each level of the hierarchy. Try this;
DECLARE #Goals TABLE (GoalId INT, GoalParentID INT, Goalstatement VARCHAR(100))
INSERT #Goals VALUES
(1, 0, 'abc'),
(2, 0, 'def'),
(3, 1, 'acc'),
(4, 2, 'efc'),
(5, 3, 'dec'),
(6, 0, 'efc'),
(7, 3, 'jhg')
;WITH NumberedGoals(GoalId, GoalParentID, Goalstatement, GoalSequence) AS (
SELECT
GoalId, GoalParentID, Goalstatement, ROW_NUMBER() OVER (PARTITION BY GoalParentID ORDER BY GoalId) AS GoalSequence
FROM
#Goals
), Hierarchy(GoalID, GoalParentID, GoalSequence, Parents)
AS
(
SELECT GoalID, GoalParentID, GoalSequence, CAST(GoalSequence AS VARCHAR(MAX))
FROM NumberedGoals AS FirtGeneration
WHERE GoalParentID = 0
UNION ALL
SELECT NextGeneration.GoalID, NextGeneration.GoalParentID, NextGeneration.GoalSequence,
CAST(CASE WHEN Parent.Parents = ''
THEN(CAST(NextGeneration.GoalSequence AS VARCHAR(MAX)))
ELSE(Parent.Parents + '.' + CAST(NextGeneration.GoalSequence AS VARCHAR(MAX)))
END AS VARCHAR(MAX))
FROM NumberedGoals AS NextGeneration
INNER JOIN Hierarchy AS Parent ON NextGeneration.GoalParentID = Parent.GoalID
)
SELECT h.Parents as [Serial no], h.GoalId, h.GoalParentId, g.GoalStatement
FROM Hierarchy h
JOIN #Goals g ON g.GoalID = h.GoalID
OPTION (MAXRECURSION 32767)
;with Hierarchy
as
(
select GoalID,
ParentId,
Row_Number() over(partition by ParentId order by GoalID) as number,
cast(Row_Number() over(partition by ParentId order by GoalID) as nvarchar(200)) newnumber
from Goals where ParentId = 0
Union All
Select p.GoalId,
p.ParentId,
Row_Number() over(partition by p.ParentId order by p.GoalID) as number,
cast(cte.newnumber + '.' + cast(Row_Number() over(partition by p.ParentId order by p.GoalID) as nvarchar(200)) as nvarchar(200)) newnumber
From Goals p
Join Hierarchy cte On cte.GoalId = p.ParentId
)
select * from Hierarchy

Resources