Insert history into a new table - sql-server

I'm working on this table as shown below it has name, date,id and key. I would like to insert into new table where the old_name column maintains the change in name for that key. The output result is shown below as well. Thanks
id name date Key
1 charles 2004-05-07 1001
2 CON 2004-05-07 1001
3 Virginia 2006-09-08 1001
4 MART 2012-01-03 1001
5 McDonalds 2013-12-30 1001
OUTPUT
id old_name name date Key
1 NULL charles 2004-05-07 1001
2 charles CON 2004-05-07 1001
3 CON Virginia 2006-09-08 1001
4 Virginia MART 2012-01-03 1001
5 MART McDonalds 2013-12-30 1001

Seems like a good fit for LAG()
Select id
,old_name = lag(name,1) over (Partition By [Key] Order by ID)
,name
,date
,[key]
From YourTable
Order By ID

You can use lag if it is SQL Server >=2012
select *, lag(name,1,null) over(order by id) Old_name from #yourhistory
Your input table
create table #yourhistory (id int, name varchar(20), date date, [key] int)
insert into #yourhistory
( id , name , date , [Key] ) values
( 1 ,'charles ','2004-05-07', 1001 )
,( 2 ,'CON ','2004-05-07', 1001 )
,( 3 ,'Virginia ','2006-09-08', 1001 )
,( 4 ,'MART ','2012-01-03', 1001 )
,( 5 ,'McDonalds','2013-12-30', 1001 )

Related

How to pivot wider these dataset

My test dataset
IdCx FecCx OrderId Value
1234 2022-08-15 1 07:50
1234 2022-08-15 2 08:00
1234 2022-08-15 3 08:24
5678 2022-08-16 1 14:45
5678 2022-08-16 3 15:30
I require to pivot wider based on OrderId and Value
My expected result will look like (I do need the NULL in Val2)
IdCx FecCx Val1 Val2 Val3
1234 2022-08-15 07:50 08:00 08:24
5678 2022-08-16 14:45 NULL 15:30
My first approach has been with CASE but resulting dataset will not coalesce rows, leaving a lot of undesired nulls
My dbFiddle
You simply need to aggregate - this collapses your NULL values into one row per group:
select idCx, FecCx
,max(case when OrderId = 1 then Value end) as Val1
,max(case when OrderId = 2 then Value end) as Val2
,max(case when OrderId = 3 then Value end) as Val3
from dbo.fact1
group by idCx, FecCx;
See modified Fiddle
Just in case ORderID is not sequential, we use the window function row_number() over() in concert with a PIVOT
Example or dbFiddle
Select *
From (
Select IDcx
,FecCx
,Item = concat('Val',row_number() over (partition by idcx,FecCx order by OrderID) )
,Value
From fact1
) src
Pivot ( max(Value) for Item in ([Val1],[Val2],[Val3])) pvt

How to filter columns with multiple values for each ID in SQL Server

I have a result set as below and I want to select a single record when the same ID has 2 records with different values for Age and status column, for example
Please see the result set below where ID, name, country name coming from table A and Age, Active status coming from b table
ID name country Age status
----------------------------------------------
1 Prasad India NULL NULL
2 John USA NULL NULL
3 GREG AUS NULL NULL
4 RAVI India NULL NULL
4 RAVI India 18 Years and Above 1
Go with this:
Select *
From
(
Select t2.*,
ROW_NUMBER() over(partition by ID order by name,country,Age, status desc) as rn
From yourtable t2
)
Where rn = 1

parent id hierarchy identification MS SqlServer2012

I have this code
create table #temp
(
order_id int not null identity(1,1) primary key
,sid int
,created_date date
,parent_order_id int
)
insert into #temp
(
sid
,created_date
)values(1,'2017-01-01')
insert into #temp
(
sid
,created_date
,parent_order_id
)values(1,'2017-02-01',1),(1,'2017-03-01',2),(1,'2017-04-01',3)
insert into #temp
(
sid
,created_date
)values(1,'2017-06-01')
insert into #temp
(
sid
,created_date
,parent_order_id
)values(1,'2017-07-01',5),(1,'2017-08-01',6)
select * from #temp
Whenever parent_order_id is null which indicates it is a new order. After that customer can add items associated to that order. so we have parent_order_id filled for these associations. But I want to know what is the first order_id for each association child order.I am looking for an output like below.
`order_id sid created_date parent_order_id original_order_id
1 1 2017-01-01 NULL 1
2 1 2017-02-01 1 1
3 1 2017-03-01 2 1
4 1 2017-04-01 3 1
5 1 2017-06-01 NULL 4
6 1 2017-07-01 5 4
7 1 2017-08-01 6 4
`
any help is appreciated. Thanks in advance.
With the following piece of code you can get results you are expecting.
;WITH cte (order_id, original_order_id)
AS
(
SELECT order_id, order_id AS original_order_id
FROM #temp WHERE parent_order_id IS NULL
UNION ALL
SELECT o.order_id AS order_id, cte.original_order_id AS original_order_id
FROM #temp AS o
JOIN cte
ON o.parent_order_id = cte.order_id
)
SELECT #temp.order_id, #temp.sid, #temp.created_date, #temp.parent_order_id, cte.original_order_id
FROM #temp
JOIN cte ON cte.order_id=#temp.order_id
ORDER BY cte.order_id
Please be aware, that there are certain limits on recursion as this for CTE. Currently it is 100 which can be pushed up to 32767.

Combining multiple rows in SQL with distinct identifier

I'm pulling some data from SQL Server from this table.
ID_Number Date_01 Date_02 Date_03 Date_04 Date_05
---------------------------------------------------------------------
1001 6/1/2015 6/5/2015 Null Null 6/6/2015
1001 Null Null 6/5/2015 Null 6/7/2015
1002 6/20/2015 Null Null 6/21/2015 Null
1002 6/21/2015 6/22/2015 6/23/2015 6/19/2015 6/20/2015
1003 6/25/2015 Null Null 6/26/2015 6/29/2015
I'm not sure what CTE query will I use to return only one row per ID and get the max date per column for each ID.
Here's the sample result:
ID_Number Date_01 Date_02 Date_03 Date_04 Date_05
----------------------------------------------------------------------
1001 6/1/2015 6/5/2015 6/5/2015 Null 6/7/2015
1002 6/21/2015 6/22/2015 6/23/2015 6/21/2015 6/20/2015
1003 6/25/2015 Null Null 6/26/2015 6/29/2015
You don't need CTE to do this, If am not wrong simple Group by with Max aggregate should work for you
select
ID_Number,
Date_01=max(Date_01),
Date_02=max(Date_02),
Date_03=max(Date_03),
Date_04=max(Date_04),
Date_05=max(Date_05)
from yourtable
group by ID_Number
max date per column for each ID
Grouping by ID_Number :
SELECT ID_Number AS Expr1, MAX(Date_01) AS Date_01, MAX(Date_02) AS Date_02, MAX(Date_03) AS Date_03, MAX(Date_04) AS Date_04, MAX(Date_05) AS Date_05
FROM ta1
GROUP BY ID_Number

replace NULL values with latest non-NULL value in resultset series (SQL Server 2008 R2)

for SQL Server 2008 R2
I have a resultset that looks like this (note [price] is numeric, NULL below represents a
NULL value, the result set is ordered by product_id and timestamp)
product timestamp price
------- ---------------- -----
5678 2008-01-01 12:00 12.34
5678 2008-01-01 12:01 NULL
5678 2008-01-01 12:02 NULL
5678 2008-01-01 12:03 23.45
5678 2008-01-01 12:04 NULL
I want to transform that to a result set that (essentially) copies a non-null value from the latest preceding row, to produce a resultset that looks like this:
product timestamp price
------- ---------------- -----
5678 2008-01-01 12:00 12.34
5678 2008-01-01 12:01 12.34
5678 2008-01-01 12:02 12.34
5678 2008-01-01 12:03 23.45
5678 2008-01-01 12:04 23.45
I don't find any aggregate/windowing function that will allow me to do this (again this ONLY needed for SQL Server 2008 R2.)
I was hoping to find an analytic aggregate function that do this for me, something like...
LAST_VALUE(price) OVER (PARTITION BY product_id ORDER BY timestamp)
But I don't seem to find any way to do a "cumulative latest non-null value" in the window (to bound the window to the preceding rows, rather than the entire partition)
Aside from creating a table-valued user defined function, is there any builtin that would accomplish this?
UPDATE:
Apparently, this functionality is available in the 'Denali' CTP, but not in SQL Server 2008 R2.
LAST_VALUE http://msdn.microsoft.com/en-us/library/hh231517%28v=SQL.110%29.aspx
I just expected it to be available in SQL Server 2008. It's available in Oracle (since 10gR2 at least), and I can do something similar in MySQL 5.1, using a local variable.
http://download.oracle.com/docs/cd/E14072_01/server.112/e10592/functions083.htm
You can try the following:
* Updated **
-- Test Data
DECLARE #YourTable TABLE(Product INT, Timestamp DATETIME, Price NUMERIC(16,4))
INSERT INTO #YourTable
SELECT 5678, '20080101 12:00:00', 12.34
UNION ALL
SELECT 5678, '20080101 12:01:00', NULL
UNION ALL
SELECT 5678, '20080101 12:02:00', NULL
UNION ALL
SELECT 5678, '20080101 12:03:00', 23.45
UNION ALL
SELECT 5678, '20080101 12:04:00', NULL
;WITH CTE AS
(
SELECT *
FROM #YourTable
)
-- Query
SELECT A.Product, A.Timestamp, ISNULL(A.Price,B.Price) Price
FROM CTE A
OUTER APPLY ( SELECT TOP 1 *
FROM CTE
WHERE Product = A.Product AND Timestamp < A.Timestamp
AND Price IS NOT NULL
ORDER BY Product, Timestamp DESC) B
--Results
Product Timestamp Price
5678 2008-01-01 12:00:00.000 12.3400
5678 2008-01-01 12:01:00.000 12.3400
5678 2008-01-01 12:02:00.000 12.3400
5678 2008-01-01 12:03:00.000 23.4500
5678 2008-01-01 12:04:00.000 23.4500
I have a table containing the following data. I want to update all nulls in salary columns with previous value without taking null value.
Table:
id name salary
1 A 4000
2 B
3 C
4 C
5 D 2000
6 E
7 E
8 F 1000
9 G 2000
10 G 3000
11 G 5000
12 G
here is the query that works for me.
select a.*,first_value(a.salary)over(partition by a.value order by a.id) as abc from
(
select *,sum(case when salary is null then 0 else 1 end)over(order by id) as value from test)a
output:
id name salary Value abc
1 A 4000 1 4000
2 B 1 4000
3 C 1 4000
4 C 1 4000
5 D 2000 2 2000
6 E 2 2000
7 E 2 2000
8 F 1000 3 1000
9 G 2000 4 2000
10 G 3000 5 3000
11 G 5000 6 5000
12 G 6 5000
Try this:
;WITH SortedData AS
(
SELECT
ProductID, TimeStamp, Price,
ROW_NUMBER() OVER(PARTITION BY ProductID ORDER BY TimeStamp DESC) AS 'RowNum'
FROM dbo.YourTable
)
UPDATE SortedData
SET Price = (SELECT TOP 1 Price
FROM SortedData sd2
WHERE sd2.RowNum > SortedData.RowNum
AND sd2.Price IS NOT NULL)
WHERE
SortedData.Price IS NULL
Basically, the CTE creates a list sorted by timestamp (descending) - the newest first. Whenever a NULL is found, the next row that contains a NOT NULL price will be found and that value is used to update the row with the NULL price.

Resources