I have these two tables
ItemMov
Item Date
A 2018-03-31
A 2018-03-30
A 2018-03-25
B 2018-03-28
B 2018-03-29
and DateTable
Date
2018-03-31
2018-03-30
2018-03-29
2018-03-28
2018-03-27
2018-03-26
2018-03-25
What i need is to have a sort of cross product between those two but limited to the earlest date for each item.
Initially i used simple cross product.
select distinct t.Item, f.Date from ItemMov t cross join DateTable f
getting this
Item Date
A 2018-03-31
A 2018-03-30
A 2018-03-29
A 2018-03-28
A 2018-03-27
A 2018-03-26
A 2018-03-25
B 2018-03-31
B 2018-03-30
B 2018-03-29
B 2018-03-28
B 2018-03-27
B 2018-03-26
B 2018-03-25
Of course this crossing brings dates early than the first date for some items, like B.
The desired output should be something like that but limited to the min(date) for each item. So, is there a why of doing this with crossing tables or should a use some sort of loop?
Desired output
Item Date
A 2018-03-31
A 2018-03-30
A 2018-03-29
A 2018-03-28
A 2018-03-27
A 2018-03-26
A 2018-03-25
B 2018-03-31
B 2018-03-30
B 2018-03-29
B 2018-03-28
Consider a join with on clause date expression:
select distinct t.Item, f.Date
from ItemMov t
inner join DateTable f on t.Date <= f.Date
-- cross join DateTable f on t.Date <= f.Date
order by t.Item, f.Date desc
Rextester demo
You can aggregate before doing a join:
select i.item, d.date
from (select i.item, min(date) as min_date, max(date) as max_date
from itemmov i
group by i.item
) i join
datetable d
on d.date >= i.min_date and d.date <= i.max_date
order by i.item, d.date;
Related
I have table a auctions and table b bids:
Table a (Auctions):
id status
1 1
2 0
3 0
4 1
Table b (Bids):
id auction_id amount date
1 1 0.1 2018-01-24
2 1 0.1 2018-01-24
3 4 0.2 2018-01-26
4 4 0.1 2018-01-26
5 4 0.3 2018-01-28
6 1 0.1 2018-01-29
What I want to get is the amount of bids, the total sum of bids, the last bid date per auction from table b in addition to their id and status from table a everything ordered by status:
Something like this:
id status bid_sum bid_count last_bid_date
4 1 0.6 3 2018-01-28
1 1 0.3 3 2018-01-29
3 0 0 0 0000-00-00
2 0 0 0 0000-00-00
So far I have this query:
SELECT a.id, a.status, SUM( b.amount ) as bids_sum, COUNT( b.id ) as bids_count, MAX( b.dt ) as last_bid_date
FROM a, b
GROUP BY a.id
ORDER BY a.status DESC, a.id DESC
The problem is that it is returning only auctions that have at least 1 bid
id status bid_sum bid_count last_bid_date
4 1 0.6 3 2018-01-28
1 1 0.3 3 2018-01-29
And I need all auctions. Can you please help? Thank you!
SELECT
a.id,
a.status,
COALESCE(SUM(b.amount), 0) as bids_sum,
COUNT(b.id) as bids_count,
COALESCE(MAX(b.dt), '0000-00-00') as last_bid_date
FROM a left outer join b
on a.id = b.auction_id
GROUP BY a.id
ORDER BY a.status DESC, a.id DESC
What you want to do is a left join:
SELECT a.id,
a.status,
SUM(b.amount) AS bids_sum,
COUNT(b.id) AS bids_count,
MAX(b.dt) AS last_bid_date
FROM a
LEFT JOIN b ON a.id = b.auction_id
GROUP BY a.id
ORDER BY a.status DESC,
a.id DESC
I have tables as below -
Employee -
Employee_Id Name Limit_Amt
1 Sachin 3000
2 Mahi 2500
Employee_Wage -
Employee_Id Amount Pay_Date
1 200 2017-01-01
1 250 2017-02-01
1 300 2017-03-01
2 350 2017-01-01
2 400 2017-02-01
2 300 2017-03-01
Now to find out Remaining limit for individual employee below query works fine -
SELECT e.Limit_Amt - SUM(Amount) AS 'Remaining Limit'
FROM Employee e, Employee_Wage ew
WHERE e.Employee_Id = ew.Employee_Id
GROUP BY e.Employee_Id, e.Limit_Amt
It gives output as -
Remaining Limit
2250
1450
But, further I wish to calculate Total of remaining limit (i.e. deriving 3700), then if I apply SUM(e.Limit_Amt - SUM(Amount)) ... it's not working.
Conceptually I am blocked. Could someone please guide me here? Thanks in advance.
You could use a subquery:
SELECT SUM(remaining)
FROM (
SELECT e.Limit_Amt - SUM(Amount) AS remaining
FROM Employee e
JOIN Employee_Wage ew
ON e.Employee_Id = ew.Employee_Id
GROUP BY
e.Employee_Id
, e.Limit_Amt
) sub
The from a join b on a.id = b.id syntax is clearer than SQL92's from a, b where a.id = b.id.
select e.Name,e.Limit_Amt,sum(cast(w.Amount as int)) 'sum',
e.Limit_Amt-sum(cast(w.Amount as int)) 'Remaining'
from Employee e join Employee_Wage w
on e.Employee_Id=w.Employee_Id
group by e.Name,e.Limit_Amt
I am using two table named Transactions and Items. Refer below
Table 1 : Transactions
C_ID - State - Time
1 Start 2016-07-13 16:02:42
1 Passed 2016-07-13 20:28:21
2 Passed 2016-07-11 17:39:13
3 Passed 2016-07-07 20:23:00
4 Start 2016-07-01 13:19:54
4 Passed 2016-07-01 17:37:41
5 Start 2016-07-07 16:16:21
5 Passed 2016-07-07 21:04:01
6 Passed 2016-07-07 21:11:39
7 Passed 2016-07-08 20:30:46
Table 2 : Items
C_No - C_ID
C1 - 5
C2 - 3
C3 - 9
C4 - 7
C5 - 6
C6 - 8
C7 - 2
C8 - 4
C9 - 10
C10 - 1
I would like to join these tables and need output as mentioned below;
Output
C_No - State - Time
C10 - Start 2016-07-13 16:02:42
C10 - Passed 2016-07-13 20:28:21
C8 - Start 2016-07-01 13:19:54
C8 - Passed 2016-07-01 17:37:41
C1 - Start 2016-07-07 16:16:21
C1 - Passed 2016-07-07 20:00:01
In addition to join two tables, I want a filter on State and Time. The conditions are (State = 'Start' and Time <= 17:00) and (State = 'Passed' and Time <= 21:00)
I don't want any item doesn't have both Start and Passed.
I used the following query
{SELECT distinct(c.C_No), p.State, p.Time FROM Items c
inner join Transitions p on p.c_id = c.c_id and date(p.Time) between '2016-07-01' and CURRENT_DATE()
and ((p.State = 'Start' and time(p.Time) <= '17:00:00') or p.State = 'Passed' )
order by c.C_No, State;}
SQLFiddle added to question.
Try this statement
select c_no,state,time from transactions inner join items on transactions.c_id=items.c_id where (state='Start' and right(time,8)<='17:00:00') or (state='Passed' and right(time,8)<='21:00:00')
In your question, with your sample data, I don't think C1 should exist in the result, because when C_ID = 5, and its State is 'Passed' and its Time is '2016-07-07 21:04:01', it does not match your condition. So try this:
select t2.C_No, t.`State`, t.`Time`
from Transactions t
join (
select C_ID
from Transactions
where (State = 'Start' and time(`Time`) <= '17:00:00')
or (State = 'Passed' and time(`Time`) <= '21:00:00')
group by C_ID
having count(distinct State) > 1
) t1 on t.C_ID = t1.C_ID
left join Items t2 on t1.C_ID = t2.C_ID
order by t2.C_No, t.`State`;
SqlFiddle Demo
Ideas as follows:
with t_start as (
select t2.c_no, t1.state, t1.time
from transactions t1
inner join items t2 on t2.c_id=t1.c_id
where t1.state='State' and time(t1.time)<='17:00:00'
) t_passed as(
select t2.c_no, t1.state, t1.time
from transactions t1
inner join items t2 on t2.c_id=t1.c_id
where t1.state='Passed' and time(t1.time)<='21:00:00'
) t_total as(
select * from t_start
union
select * from t_passed
)
select * from t_total order by c_no, state;
I'm loking for one logic that might be not accepatable.
But my requirement is I want count of customers(NewCustomers, repeatCustomers) on the basis of previous and current month
Like from this data I want
DATE NAME
2016-01-01 A
2016-01-01 B
2016-01-01 C
2016-01-05 E
2016-01-05 F
2016-01-25 G
2016-01-25 H
2016-02-25 A
2016-02-25 E
2016-02-10 X
2016-02-11 Y
2016-02-13 F
Output like this
MONTH NewCustomer RepeatCustomer CustomerCount of refernece month (Like here is JAN)
FEB 2 3 7
Same will go for next months
Any suggestion ? Thanks !!
I don't know what the reference month is, but you can get the first two columns by combining the first time you see a customer with who visits in each month:
select date_format(c.date, '%Y-%m') as yyyymm,
count(distinct c.name) as NumCustomers,
sum(case when date_format(c.date, '%Y-%m') <> date_format(cc.start_date, '%Y-%m')
then 1 else 0
end) as NumRepeatCustomers
from customers c join
(select c.name, min(c.date) as start_date
from customers c
group by c.name
) cc
on c.name = cc.name
group by date_format(c.date, '%Y-%m')
order by yyyymm;
I have a table like following columns:
id date price pid
---------------------------
1 2015-02-01 34 2
2 2015-02-02 34 2
3 2015-02-03 34 2
4 2015-02-04 78 2
5 2015-02-05 78 2
6 2015-02-06 78 2
7 2015-02-07 52 2
8 2015-02-08 52 2
9 2015-02-09 52 2
10 2015-02-10 34 2
11 2015-02-11 34 2
12 2015-02-12 34 2
Now I want following result:
date_from date_to price pid
-------------------------------------
2015-02-01 2015-02-03 34 2
2015-02-04 2015-02-06 78 2
2015-02-07 2015-02-09 52 2
2015-02-10 2015-02-12 34 2
IMPORTANT:
I don't want to group the price "34" in this case.
One solution i can think of using user defined variables also i assume the id part is set to auto_increment
select min(t1.date) date_from,
max(t1.date) date_to,
t1.price,
t1.pid
from (
select t.*,
#r:= case when #g = price then #r else #r + 1 end r,
#g:= price g
from test t
cross join (select #g:=null,#r:=0) t
order by id
) t1
group by t1.r
DEMO
Borrowing M Khalid Junaid's fiddle...
SELECT a.date date_from
, MIN(c.date) date_to
, price
, pid
FROM test a
LEFT
JOIN test b
ON b.pid = a.pid
AND b.price = a.price
AND b.id = a.id - 1
LEFT
JOIN test c
ON c.pid = a.pid
AND c.price = a.price
AND c.id >= a.id
LEFT
JOIN test d
ON d.pid = a.pid
AND d.price = a.price
AND d.id = c.id + 1
WHERE b.id IS NULL
AND c.id IS NOT NULL
AND d.id IS NULL
GROUP
BY a.id, a.price, a.pid;
http://sqlfiddle.com/#!2/478f9/6
Try below query, it will group by three records on basis of date and price
SELECT min(created) AS date_from, max(created) AS date_to, price, pid
FROM t1
GROUP BY price, floor(DATEDIFF("2015-02-01", created) / 3);
Try this in MySQL. Here app_date is Date in your question:
set #rownum=1;
select min(app_date),max(app_date),price,pid from
(select t.id1 id,t.app_date app_date,t.price1 price,t.pid pid,
case when (t.price1=t.price2 or t.price2 is null) then #rownum else #rownum:=#rownum+1 end temp_num from
(select a.id id1,b.id id2,a.app_date app_date,a.price price1,b.price price2,a.pid pid from
test a left outer join test b on a.id=b.id+1) t
order by id1) temp
group by price,pid,temp_num
order by min(app_date);