Concrete Rows of Id 2 with Id 1 IF Date is Same and All Row Names Should be different in SQL Server 2008R2 and - sql

I have following Data in myRecords Table
Id Date Name Cash
1 11/25/2016 4:23.123 Ramesh 10000
2 11/25/2016 4:23.173 Suresh 15000
1 11/27/2016 5:23.320 Ramesh 30000
2 11/27/2016 5:23.670 Suresh 40000
and I want to create view So I can get data in following Format
Id1 Date1 Name1 Cash1 Id2 Date2 Name2 Cash2
1 11/25/2016 4:23.123 Ramesh 10000 2 11/25/2016 4:23.173 Suresh 15000
1 11/27/2016 5:23.320 Ramesh 30000 2 11/27/2016 5:23.670 Suresh 40000
How can I do it.

If you are doing date and there will always only be 2 records per day you could convert to drop off the time and do a self join:
DECLARE #myRecords AS TABLE (Id INT, DATE DATETIME, Name VARCHAR(20), CASH INT)
INSERT INTO #myRecords VALUES (1,'11/25/2016 4:23','Ramesh',10000),(2,'11/25/2016 4:23','Suresh',15000)
,(1,'11/27/2016 5:23','Ramesh',30000),(2,'11/27/2016 4:23','Suresh',40000)
SELECT
m1.Id as Id1
,m1.Date as Date1
,m1.Name as Name1
,m1.Cash as Cash1
,m2.Id as Id2
,m2.Date as Date2
,m2.Name as Name2
,m2.Cash as Cash2
FROM
#myRecords m1
LEFT JOIN #myRecords m2
ON CAST(m1.DATE AS DATE) = CAST(m2.DATE AS DATE)
AND m1.Id <> m2.Id
WHERE
m1.Id = 1
Then you can also introduce ROW_NUMBER() to figure out whatever order you want then take all of the ODD RowNumbers and SELF JOIN to the Even RowNumbers:
;WITH cte AS (
SELECT
*
,RowNum = ROW_NUMBER() OVER (ORDER BY Date)
FROM
#myRecords
)
SELECT *
FROM
cte c1
LEFT JOIN cte c2
ON c1.RowNum + 1 = c2.RowNum
WHERE
c1.RowNum % 2 <> 0

As long as your Id joining logic is unclear, this will help In this case but you will need to add Id Filter or additional Identity column and row_number() in future I guess.
SELECT
T.*, TT.*
FROM
[Table] AS T
INNER JOIN
[Table] AS TT
ON T.Date = TT.Date

You can use Cross Apply for the required result set.
SELECT [ID],
[DATE],
[NAME],
[CASH],
B.*
FROM #TABLE1 A
CROSS APPLY (SELECT ID AS ID2,
[DATE] AS DATE2,
[NAME] AS NAME2,
[CASH] AS CASH2
FROM #TABLE1 B
WHERE A.ID < B.ID
AND CONVERT(DATE, A.DATE) = CONVERT(DATE, B.DATE))B

This will also return the same result:
select a.id, a.date, a.name, a.cash, b.id as id2, b.date as date2,
b.name as name2, b.cash as cash2
from myTable a
inner join myTable b on a.id+1 = b.id
and cast(a.date as date) <> cast(b.date as date)

Related

SQL Select a value from the history table based on a date

I have two tables, which one table (table A) contains the users' payment data, and the other (Table B) contains the users' rank history.
Table A
IDNO LName FName Start_Date PayType Current_Rank
------------------------------------------------------------
SJ01 Smith John 11/13/2016 Cert AC
DJ01 Doe Jack 10/20/2020 Assignment BC
Table B
IDNO Date Rank
----------------------
SJ01 10/01/2010 CAP
SJ01 10/01/2016 BC
SJ01 10/01/2020 AC
DJ01 01/01/2010 LT
DJ01 01/01/2015 CAP
DJ01 01/01/2020 BC
I need to show the user's rank according to the start_date from the table A and bring in the rank from the table B. So my end result can look like this:
IDNO LName FName Start_Date PayType Rank
------------------------------------------------------------
SJ01 Smith John 11/13/2016 Cert BC
DJ01 Doe Jack 10/20/2020 Assignment BC
How can I join these two tables and compare the dates, so that I can bring in the rank from the history table based on the start_date from the table A?
Another very simple way is to just select the corresponding Rank directly using a correlated query
select a.*,
(select top(1) [rank] from TableB b
where b.idno=a.idno and a.start_date>b.date
order by b.date desc) as [Rank]
from TableA a
here is one way:
select a.* , c.Rank From TableA a
cross apply (select top 1 * from tableB b
where a.IdNo = b.IDno
and a.Start_Date > b.date
order by b.date desc
) c
;WITH CTE
AS
(
SELECT A.IDNO,A.LName,A.FName,A.Start_Date,A.PayType,B.Rank,RNo=ROW_NUMBER() OVER(PARTITION BY B.IDNO ORDER BY B.DATE DESC)
FROM Table_B B
JOIN Table_A A ON B.IDNO=A.IDNO AND A.Start_Date>=B.Date
) SELECT IDNO,LName,FName,Start_Date,PayType,Rank
FROM CTE WHERE RNo=1
ORDER BY Start_Date
select idno, lname, fname, start_date, paytype, pp.rank current_rank
from
(select xx.idno, xx.rank, min(xx.datediff) from
(select tableA.idno, tableA.start_date - tableB.date datediff, tableB.rank
from tableA, tableB
where tableA.idno = tableB.idno) XX
group by xx.idno, xx.rank)pp,
tableA
where tableA.idno = pp.idno

Calculate only distinct values

I have a table and i want output as given below
want only distinct values.
I used cross apply but doesn't work.
Customer Book
C1 B1
C2 B1
C3 B1
I need output: All combination of all customers. Only distinct values
Example:
Customers
C1,C2
C1,C3
C2,C3
You can do this with Primary key column
CREATE TABLE #TAB( ID INT IDENTITY,Customer VARCHAR(10), Book VARCHAR(10))
INSERT INTO #TAB
SELECT 'C1','B1'
UNION ALL
SELECT 'C2','B1'
UNION ALL
SELECT 'C3','B1'
SELECT T2.Customer ,T.Customer
FROM #TAB T
INNER JOIN #TAB T2 ON T.ID >T2.ID
Result :
+----------+----------+
| Customer | Customer |
+----------+----------+
| C1 | C2 |
| C1 | C3 |
| C2 | C3 |
+----------+----------+
This should work, at least for your sample data and the narrative:
select distinct case when t1.customer > t2.customer then t2.customer + ',' + t1.customer else t1.customer + ',' + t2.customer end
from tbl t1
join tbl t2
on t1.book = t2.book
and t1.customer <> t2.customer
If you want customers with the same book, query should be something similar. Note the < operator, since we want (C1, C2), not (C2, C1):
select distinct a.customer_col , b.customer_col
from customer_table a join customer_table b
on a.book_col = b.book_col and a.customer_col < b.customer_col
Hoping i understood question correctly,
Please check below query. Please replace table and columns with your original one.
Rextester link - http://rextester.com/RPPXQO21553
select
a.customer_col , b.customer_col , a.rn , b.rn
from
(select customer_col , row_number() over (order by customer_col) rn from customer_table) a join
(select customer_col , row_number() over (order by customer_col) rn from customer_table) b
on a.customer_col <> b.customer_col
and a.rn < b.rn
order by 1
;
You can achieve this using self join (hope you want customers with the same book), Sample script below
select t1.customer,t2.customer
from #tble t1
inner join #tble t2 on t1.book = t2.book
and t1.customer < t2.customer
I got my answer as
select B,A from(select a.customer A,b.customer B, ROW_NUMBER() over(order by a.customer)rn from CustomerData a
JOIN CustomerData b ON a.customer>b.customer )x

Calculating de-cumulatived values in TSQL?

Given a table of cars and their odometer reading at various dates (first of each month), how can I write TSQL (ideally, for use as a SQL Server view) to return the "incremental" values?
In other words, I want the reverse operation from Calculate a Running Total in SQL Server.
Example:
On this table:
CarId | Date | Mileage
---------------------------
1 1/1/2000 10000
1 2/1/2000 11000
1 3/1/2000 12000
2 1/1/2000 10000
2 2/1/2000 11001
2 3/1/2000 12001
3 1/1/2000 10000
(missing datapoint for (3, 2/1/2000))
3 3/1/2000 12000
We'd return something like (the details/edge cases are flexible):
CarId | Date | Delta
---------------------------
1 1/1/2000 10000
1 2/1/2000 1000
1 3/1/2000 1000
2 1/1/2000 10000
2 2/1/2000 1001
2 3/1/2000 1000
3 1/1/2000 10000
3 3/1/2000 2000
This should work for SQL 2005 or higher:
WITH cteData As
(
SELECT
CarId,
Date,
Mileage,
ROW_NUMBER() OVER (PARTITION BY CarId ORDER BY Date) As RowNumber
FROM
dbo.Cars
)
SELECT
C.CarId,
C.Date,
CASE
WHEN P.CarId Is Null THEN C.Mileage
ELSE C.Mileage - P.Mileage
END As Delta
FROM
cteData As C
LEFT JOIN cteData As P
ON P.CarId = C.CarId
And P.RowNumber = C.RowNumber - 1
ORDER BY
C.CarId,
C.Date
;
SQL Fiddle
NB: This assumes that "missing datapoint for (3, 2/1/2000)" means that there is no row in the table for car 3, February 2000.
Same approach as the one from #Richard Deeming, but this one regards possible null values as included in original question.
;with cte ( rn, id, date, mileage )
as
(
select
row_number() over ( partition by id order by id, date )
, id
, date
, mileage
from
cars
where
mileage is not null
)
select
"current".id
, "current".date
, delta = isnull( "current".mileage - predecessor.mileage, "current".mileage )
from
cte as "current"
left join cte as predecessor
on "current".id = predecessor.id
and "current".rn - 1 = predecessor.rn
See SQL-Fiddle.
Trying to do this without dependence on any 2012 functions, cursor, while loop, etc.
This works within some limitation -- namely, the null-entry for car#3's entry is a problem for it:
DECLARE #cars table ([id] int, [date] smalldatetime, [mileage] int)
INSERT INTO #cars ([id], [date], [mileage])
SELECT 1, '1/1/2000', 10000 UNION ALL
SELECT 1, '2/1/2000', 11000 UNION ALL
SELECT 1, '3/1/2000', 12000 UNION ALL
SELECT 2, '1/1/2000', 10000 UNION ALL
SELECT 2, '2/1/2000', 11000 UNION ALL
SELECT 2, '3/1/2000', 12000 UNION ALL
SELECT 3, '1/1/2000', 10000 UNION ALL
SELECT 3, '2/1/2000', NULL UNION ALL
SELECT 3, '3/1/2000', 12000
SELECT t1.id, t1.date, t1.mileage, t2.id, t2.date, t2.mileage, t1.mileage - t2.mileage as miles FROM #cars t1
LEFT JOIN #cars t2
ON t1.id = t2.id
AND t1.date = DATEADD(MONTH,1, t2.date)
Window functions are great. But SQL Server does not have the one you need until SQL Server 2012. There, you have the lag function:
select t.*,
(Milage - lag(Milage) over (partition by carId order by date)) as Delta
from t
For earlier versions, you can use a correlated subquery:
[trouble uploading query], alas.
select t.*, (Mileage - prevMileage) as Delta
from (select t.*,
(select top 1 Mileage from t t2
 where t2.carId = t.carId and t2.date < t.date order by desc
 ) as prevDelta
from t
) t

Joining values with DateDim, where null'd dates' value will take the last non-null value in the table

I need to do a join but I'm not sure which type. I have a table like this:
Date Amount | FOO
------------------
2012-01-12 x
2012-03-14 y
2012-05-06 z
2012-05-14 aa
2012-09-02 bb
I am joining this with DateDim (Google here: DATE DIM, which is a table of dates (historical and future).
I need a query that would display data like this:
datedim.Date foo.Amount | FOO x DATEDIM
------------------------------------------
2012-01-12 x
2012-01-13 x
2012-01-14 x
... etc...
2012-03-14 y
2012-03-15 y
2012-03-16 y
2012-03-17 y
... etc...
2012-05-06 z
... etc...
Basically, I need the values to persist (were it a left join, it would be NULLs) until the next non-null value. That will persist too... etc..
What I have so far...
SELECT datedim.Date
,CASE
WHEN Amount IS NULL
THEN (SELECT TOP 1 Amount
FROM FOO WHERE foo.Date <= datedim.Date
ORDER BY Date DESC)
ELSE Amount END AS Amount
FROM DATEDIM datedim
LEFT JOIN FOO foo
ON foo.Date = datedim.Date
I need to create a view out of this. I'm getting an error saying ORDER BY is invalid for views, unless specified by TOP??? I do have a TOP in the subquery...
In SQLServer2005+ use recursive CTE
;WITH cte (id, [Date], Amount) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY [Date] ASC) AS id,
[Date], Amount
FROM dbo.your_table t1
), cte2 (id, [Date], [LevelDate], Amount) AS
(
SELECT c1.id, c1.[Date], DATEDIFF(day, c1.[Date], c2.[Date]) AS [LevelDate], c1.Amount
FROM cte c1 LEFT JOIN cte c2 ON c1.id = c2.id - 1
), cte3 (id, [Date], Amount, [Level]) AS
(
SELECT id, [Date], Amount, 1 AS [Level]
FROM cte2 c
UNION ALL
SELECT c.id, DATEADD(day, 1, ct.[Date]) AS [Date], c.Amount, ct.[Level] + 1
FROM cte2 c JOIN cte3 ct ON c.id = ct.id
WHERE c.[LevelDate] > ct.[Level]
)
SELECT [Date], Amount
FROM cte3
ORDER BY Date
OPTION (maxrecursion 0)
Demo on SQLFiddle
I'm sure there are more efficient ways using a CTE, or window functions, but something along these lines should work:
Select
d.Date,
d.FooDate,
f.Amount
From
Foo f
Inner Join (
Select
d.[Date],
Max(f.[Date]) as FooDate
From
Foo f
Inner Join
DateDim d
On f.[Date] < d.[Date]
Group By
d.[Date]
) d
On d.[FooDate] = f.[Date]
http://sqlfiddle.com/#!3/3c7d5/10

T-SQL using SUM for a running total

I have a simple table with some dummy data setup like:
|id|user|value|
---------------
1 John 2
2 Ted 1
3 John 4
4 Ted 2
I can select a running total by executing the following sql(MSSQL 2008) statement:
SELECT a.id, a.user, a.value, SUM(b.value) AS total
FROM table a INNER JOIN table b
ON a.id >= b.id
AND a.user = b.user
GROUP BY a.id, a.user, a.value
ORDER BY a.id
This will give me results like:
|id|user|value|total|
---------------------
1 John 2 2
3 John 4 6
2 Ted 1 1
4 Ted 2 3
Now is it possible to only retrieve the most recent rows for each user? So the result would be:
|id|user|value|total|
---------------------
3 John 4 6
4 Ted 2 3
Am I going about this the right way? any suggestions or a new path to follow would be great!
No join is needed, you can speed up the query this way:
select id, [user], value, total
from
(
select id, [user], value,
row_number() over (partition by [user] order by id desc) rn,
sum(value) over (partition by [user]) total
from users
) a
where rn = 1
try this:
;with cte as
(SELECT a.id, a.[user], a.value, SUM(b.value) AS total
FROM users a INNER JOIN users b
ON a.id >= b.id
AND a.[user] = b.[user]
GROUP BY a.id, a.[user], a.value
),
cte1 as (select *,ROW_NUMBER() over (partition by [user]
order by total desc) as row_num
from cte)
select id,[user],value,total from cte1 where row_num=1
SQL Fiddle Demo
add where statement:
select * from
(
your select statement
) t
where t.id in (select max(id) from table group by user)
also you can use this query:
SELECT a.id, a.user, a.value,
(select max(b.value) from table b where b.user=a.user) AS total
FROM table a
where a.id in (select max(id) from table group by user)
ORDER BY a.id
Adding a right join would perform better than nested select.
Or even simpler:
SELECT MAX(id), [user], MAX(value), SUM(value)
FROM table
GROUP BY [user]
Compatible with SQL Server 2008 or later
DECLARE #AnotherTbl TABLE
(
id INT
, somedate DATE
, somevalue DECIMAL(18, 4)
, runningtotal DECIMAL(18, 4)
)
INSERT INTO #AnotherTbl
(
id
, somedate
, somevalue
, runningtotal
)
SELECT LEDGER_ID
, LL.LEDGER_DocDate
, LL.LEDGER_Amount
, NULL
FROM ACC_Ledger LL
ORDER BY LL.LEDGER_DocDate
DECLARE #RunningTotal DECIMAL(18, 4)
SET #RunningTotal = 0
UPDATE #AnotherTbl
SET #RunningTotal=runningtotal = #RunningTotal + somevalue
FROM #AnotherTbl
SELECT *
FROM #AnotherTbl