I have a single table, and I want to pivot it to new table. I used pivot to implements but the aggregate function will filter data. How to pivot table without aggregate function, or could u can give me recommendation for this question.
Orginal Table
ID Name Value Date
1 A 5.00 06/01/2019 13:00
2 A 13.15 06/02/2019 15:32
3 B 3.20 06/02/2019 15.32
4 B 33.11 05/11/2019 13:00
5 B 32.00 05/11/2019 13:00
trans to new table
ID A B Date
1 5.00 NULL 06/01/2019 13:00
2 13.15 3.20 06/02/2019 15:32
3 NULL 33.11 05/11/2019 13:00
4 Null 32.00 05/11/2019 13:00
notes: ID is identity on two table.
my pivot code, it only keep max value.
PIVOT(
MAX(Value)
FOR Name IN (A,B)) AS S
ORDER BY Date DESC
A standard pivot query should work here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Date, Name ORDER BY ID) rn
FROM yourTable
)
SELECT
Date,
MAX(CASE WHEN Name = 'A' THEN [Value] END) AS A,
MAX(CASE WHEN Name = 'B' THEN [Value] END) AS B
FROM cte
GROUP BY
Date, rn;
Demo
Related
I have the next data: TABLE_A
RegisteredDate
Quantity
2022-03-01 13:00
100
2022-03-01 13:10
20
2022-03-01 13:20
-80
2022-03-01 13:30
-40
2022-03-02 09:00
10
2022-03-02 22:00
-5
2022-03-03 02:00
-5
2022-03-03 03:00
25
2022-03-03 03:20
-10
If I add cumulative column
select RegisteredDate, Quantity
, sum(Quantity) over ( order by RegisteredDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as Summary
from TABLE_A
RegisteredDate
Quantity
Summary
2022-03-01 13:00
100
100
2022-03-01 13:10
20
120
2022-03-01 13:20
-80
40
2022-03-01 13:30
-40
0
2022-03-02 09:00
10
10
2022-03-02 22:00
-5
5
2022-03-03 02:00
-5
0
2022-03-03 03:00
25
25
2022-03-03 03:20
-10
15
Is there a way to get the following result with a query?
RegisteredDate
Quantity
Summary
2022-03-03 03:00
25
25
2022-03-03 03:20
-10
15
This result is the last records after the last zero.
EDIT:
Really for the solution to this problem I need the: 2022-03-03 03:00 is the first date of the last records after the last zero.
You can try to use SUM aggregate window function to calculation grp column which part represent to last value accumulated.
Query 1:
WITH cte AS
(
SELECT RegisteredDate,
Quantity,
sum(Quantity) over (order by RegisteredDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as Summary
FROM TABLE_A
), cte2 AS (
SELECT *,
SUM(CASE WHEN Summary = 0 THEN 1 ELSE 0 END) OVER(order by RegisteredDate desc) grp
FROM cte
)
SELECT RegisteredDate,
Quantity
FROM cte2
WHERE grp = 0
ORDER BY RegisteredDate
Results:
| RegisteredDate | Quantity |
|----------------------|----------|
| 2022-03-03T03:00:00Z | 25 |
| 2022-03-03T03:20:00Z | -10 |
Use a CTE that returns the summary column and NOT EXISTS to filter out the rows that you don't need:
WITH cte AS (SELECT *, SUM(Quantity) OVER (ORDER BY RegisteredDate) Summary FROM TABLE_A)
SELECT c1.*
FROM cte c1
WHERE NOT EXISTS (
SELECT 1
FROM cte c2 WHERE c2.RegisteredDate >= c1.RegisteredDate AND c2.Summary = 0
)
ORDER BY c1.RegisteredDate;
There is no need for ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW in the OVER clause of the window function, because this is the default behavior.
See the demo.
Try this:
with u as
(select RegisteredDate,
Quantity,
sum(Quantity) over (order by RegisteredDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as Summary
from TABLE_A)
select * from u
where RegisteredDate >= all(select RegisteredDate from u where Summary = 0)
and Summary <> 0;
Fiddle
Basically what you want is for RegisteredDate to be >= all RegisteredDatess where Summary = 0, and you want Summary <> 0.
When using window functions, it is necessary to take into account that RegisteredDate column is not unique in TABLE_A, so ordering only by RegisteredDate column is not enough to get a stable result on the same dataset.
With A As (
Select ROW_NUMBER() Over (Order by RegisteredDate, Quantity) As ID, RegisteredDate, Quantity
From TABLE_A),
B As (
Select A.*, SUM(Quantity) Over (Order by ID) As Summary
From A)
Select Top 1 *
From B
Where ID > (Select MAX(ID) From B Where Summary=0)
ID
RegisteredDate
Quantity
Summary
8
2022-03-03 03:00
25
25
I have a table like below
AID BID CDate
-----------------------------------------------------
1 2 2018-11-01 00:00:00.000
8 1 2018-11-08 00:00:00.000
1 3 2018-11-09 00:00:00.000
7 1 2018-11-15 00:00:00.000
6 1 2018-12-24 00:00:00.000
2 5 2018-11-02 00:00:00.000
2 7 2018-12-15 00:00:00.000
And I am trying to get a result set as follows
ID MaxDate
-------------------
1 2018-12-24 00:00:00.000
2 2018-12-15 00:00:00.000
Each value in the id columns(AID,BID) should return the max of CDate .
ex: in the case of 1, its max CDate is 2018-12-24 00:00:00.000 (here 1 appears under BID)
in the case of 2 , max date is 2018-12-15 00:00:00.000 . (here 2 is under AID)
I tried the following.
1.
select
g.AID,g.BID,
max(g.CDate) as 'LastDate'
from dbo.TT g
inner join
(select AID,BID,max(CDate) as maxdate
from dbo.TT
group by AID,BID)a
on (a.AID=g.AID or a.BID=g.BID)
and a.maxdate=g.CDate
group by g.AID,g.BID
and 2.
SELECT
AID,
CDate
FROM (
SELECT
*,
max_date = MAX(CDate) OVER (PARTITION BY [AID])
FROM dbo.TT
) AS s
WHERE CDate= max_date
Please suggest a 3rd solution.
You can assemble the data in a table expression first, and the compute the max for each value is simple. For example:
select
id, max(cdate)
from (
select aid as id, cdate from t
union all
select bid, cdate from t
) x
group by id
You seem to only care about values that are in both columns. If this interpretation is correct, then:
select id, max(cdate)
from ((select aid as id, cdate, 1 as is_a, 0 as is_b
from t
) union all
(select bid as id, cdate, 1 as is_a, 0 as is_b
from t
)
) ab
group by id
having max(is_a) = 1 and max(is_b) = 1;
I have a table which has duplicate record this is how the table looks like.
ID Date Status ModifiedBy
------------------------------------------
1 1/2/2019 10:29 Assigned(0) xyz
1 1/2/2019 12:21 Pending(1) abc
1 1/4/2019 11:42 Completed(5)abc
1 1/20/2019 2:45 Closed(8) pqr
2 9/18/2018 10:05 Assigned(0) xyz
2 9/18/2018 11:15 Pending(1) abc
2 9/21/2018 11:15 Completed(5)abc
2 10/7/2018 2:46 Closed(8) pqr
What I want to do is take the minimum date value but also I want to add additional column which is PendingStartDate and PendingEndDate.
PendingStartDate: date when ID went into pending status
PendingEndDate: date when ID went from pending status to any other status
So my final output should look like this
ID AuditDate Status ModifiedBy PendingStartDate PendingEndDate
---------------------------------------------------------------------------
1 1/2/2019 10:29 Assigned(0) xyz 1/2/2019 12:21 1/4/2019 11:42
2 9/18/2018 10:05 Assigned(0) abc 9/18/2018 11:15 9/21/2018 11:15
Any help as to how to do this is appreciated.
Thanks
I think you want conditional aggregation:
select id, min(date) as auditdate,
max(case when seqnum = 1 then status end) as status,
max(case when seqnum = 1 then modifiedBy end) as modifiedBy,
min(case when status like 'Pending%' then date end) as pendingStartDate,
max(case when status like 'Pending%' then next_date end) as pendingEndDate
from (select t.*,
row_number() over (partition by id order by date) as seqnum,
lead(date) over (partition by id order by date) as next_date
from t
) t
group by id;
please try this:
Declare #Tab Table(Id int, [Date] DATETIME,[Status] Varchar(25),ModifiedBy varchar(10))
Insert into #Tab
SELECT 1,'1/2/2019 10:29','Assigned(0)','xyz' Union All
SELECT 1,'1/2/2019 11:29','Started(0)','xyz' Union All
SELECT 1,'1/2/2019 12:21','Pending(1)','abc' Union All
SELECT 1,'1/2/2019 12:21','In-Progress(1)','abc' Union All
SELECT 1,'1/4/2019 11:42','Completed(5)','abc'Union All
SELECT 1,'1/20/2019 2:45','Closed(8)','pqr' Union All
SELECT 2,'9/18/2018 10:05','Assigned(0)','xyz'Union All
SELECT 2,'9/18/2018 11:15','Pending(1)','abc' Union All
SELECT 2,'9/21/2018 11:15','Completed(5)','abc' Union All
SELECT 2,'10/7/2018 2:46','Closed(8)','pqr'
;with cte As
(
Select * ,lead(date) over (partition by id order by date) as pendingStartDate
from #Tab
Where Status in ('Assigned(0)','Pending(1)','Completed(5)')
)
,cte2 As
(
Select * , lead(pendingStartDate) over (partition by id order by date) As pendingEndDate
from cte
)
Select * from cte2 where Status ='Assigned(0)'
As you mentioned in comment, i have included few states between Assigned,pending and completed.
This is the table mytable:
identifier thedate direction
111 2017-06-03 11:20 2
111 2017-06-03 12:22 1
222 2017-06-04 12:15 1
333 2017-06-05 12:21 1
444 2017-06-05 12:39 2
444 2017-06-08 14:23 2
555 2017-06-08 15:33 1
555 2017-06-08 16:12 2
I am calculating the average hourly count of unique identifiers in Apache Hive as follows:
SELECT HOUR(thedate) as hour,
COUNT(DISTINCT identifier, CAST(thedate as date),
HOUR(thedate)) / COUNT(DISTINCT CAST(thedate as date),
HOUR(thedate)) as hourly_avg_count
FROM mytable
GROUP BY HOUR(thedate)
Now I need to add a new calculated column to the result table (not the original one). This column called newcolumn should have value A for the results of thedate from the list ["2017-06-03","2017-06-04"]. It must have value B when thedate belongs to ["2017-06-05","2017-06-06"]. The rest of values of thedate that are not included in both lists should have the value C assigned.
The resulted table should have the following columns:
newcolumn hour hourly_avg_count
A 11 0.5
A 12 1
B ... ...
C ... ...
You would just add this to the GROUP BY:
SELECT (CASE WHEN DATE(thedate) IN ('2017-06-03', '2017-06-04') THEN 'A'
WHEN DATE(thedate) IN ('2017-06-05', '2017-06-06') THEN 'B'
ELSE 'C'
END) as grp,
HOUR(thedate) as hour,
COUNT(DISTINCT identifier, CAST(thedate as date), HOUR(thedate)
) / COUNT(DISTINCT CAST(thedate as date), HOUR(thedate)) as hourly_avg_count
FROM mytable
GROUP BY HOUR(thedate),
(CASE WHEN DATE(thedate) IN ('2017-06-03', '2017-06-04') THEN 'A'
WHEN DATE(thedate) IN ('2017-06-05', '2017-06-06') THEN 'B'
ELSE 'C'
END);
USE CASE STATEMENT
SELECT CASE WHEN thedate BETWEEN '2017-06-03' AND '2017-06-04'
THEN 'A'
WHEN thedate BETWEEN '2017-06-05' AND '2017-06-06'
THEN 'B'
ELSE 'C'
END newcolumn
...
So i have been scratching my head over this one,mostly because i am on access 2010 and most of the queries i have found on the internet have commands that do not work on access.
id name date qty created
====================================================
1 abc 01/2016 20 06/07/2016 11:00
2 abc 02/2016 20 06/07/2016 11:00
3 abc 03/2016 20 06/07/2016 11:00
4 abc 01/2016 30 06/07/2016 13:00
I need to pull out a recordset like this:
id name date qty created
====================================================
2 abc 02/2016 20 06/07/2016 11:00
3 abc 03/2016 20 06/07/2016 11:00
4 abc 01/2016 30 06/07/2016 13:00
the created field is just a timestamp, the date field is a "due date". basically i need to pull out the most recent qty for each name and date. the ID is unique so i can use it instead,if its easier.
By far i've got:
SELECT m1.date, m1.name, m1.created
FROM table AS m1 LEFT JOIN table AS m2 ON (m1.created < m2.created) AND
(m1.date = m2.date)
WHERE m2.created IS NULL;
but this one gives me only the most recent conflicted data, ie. the record n°4 in my example.i also need the other two records. any thoughts?
Try using NOT EXISTS() :
SELECT * FROM YourTable t
WHERE NOT EXISTS(SELECT 1 FROM YourTable s
WHERE t.date = s.date and s.created > t.created
AND t.name = s.name)
I think you are also missing a condition so I've added it:
and t.name = s.name
You didn't tag your RDBMS, if its SQL-Server/Oracle/Postgresql you can use ROW_NUMBER() :
SELECT s.date, s.name, s.created FROM (
SELECT t.*,
ROW_NUMBER() OVER(PARTITION BY t.date,t.name ORDER BY t.created DESC) as rnk
FROM YourTable t) s
WHERE s.rnk = 1
Try this:
SELECT m1.date, m1.name, m1.qty, m1.created
FROM table AS m1
JOIN (
SELECT date, name, MAX(created) AS created
FROM table
GROUP BY date, name
) AS m2 ON m1.date = m2.date AND m1.name = m2.name AND m1.created = m2.created