For example
ID TID DATE BALANCE
1 24 02-11-2018 198
2 2 08-11-2018 199
2 3 05-11-2018 0
4 13 26-11-2018 115
4 14 28-11-2018 113
Balance for Nov-18 should be displayed as below
ID BALANCE
1 198
2 0
3 0
4 113
for id-3, 0 should be displayed since there is no balance for these id in the month of November for id -1,2 & 4 min balance should be displayed.
Most of what you want can be obtained by a simple GROUP BY and some date formatting:
select a.id,
date_format(date, '%Y-%m') as month,
coalesce(min(balance), 0) as min_balance
from accounts a
left outer join balances b
on b.id = a.id
group by a.id, date_format(date, '%Y-%m')
order by a.id, date_format(date, '%Y-%m')
Here we're using the date_format function to extract the year and month from the date value, and then grouping the results by id and the formatted date. This produces the result
id month min_balance
1 2018-11 198
2 2018-11 0
3 0
4 2018-11 113
It seems apparent that there must be another table which contains all the account values, so I added a table named accounts with these values. Change this if needed.
db<>fiddle here
Related
Table1
id
hour
date
tableValue1
tableValue2
1
3
2020-05-29
123
145
2
2
2020-05-29
1500
3400
Table2:
id
hour
date
tableValue3
tableValue4
1
1
2020-05-29
4545
3697
2
3
2020-05-29
5698
2896
Table3:
id
hour
date
tableValue5
tableValue6
1
2
2020-05-29
7841
5879
2
1
2020-05-29
1485
3987
I want to select multiple columns from different tables with one query.
Expected Output:
hour
tableValue1
tableValue3
tableValue5
1
0
4545
1485
2
1500
0
7841
3
123
5698
0
I've tried this query without success:
SELECT hour , tableValue1 WHERE date = "2020-05-29" AND hour BETWEEN 0 AND 10 FROM table1
UNION ALL
SELECT hour , tableValue3 WHERE date = "2020-05-29" AND hour BETWEEN 0 AND 10 FROM table2
UNION ALL
SELECT hour , tableValue5 WHERE date = "2020-05-29" AND hour BETWEEN 10 AND 10 FROM table3
I'm getting instead the following:
hour
tableValue1
3
123
2
1500
1
4545
3
5698
2
5879
1
3987
The columns tables have in common are hour and date, do I need to redesign database structure to link the tables, so that I can use JOIN command, but how? Or is there a sql command to select multiple column from multiple tables?
There are a couple of issues in your code:
your WHERE clause should be found after the FROM clause in your subqueries
you want different columns, but you associate only one column for each of your table: if you want three columns, each of your subqueries should return three columns
your rows are not ordered because you're missing an ORDER BY clause at the end of your code.
your rows are not aggregated to remove the zeroes in excess: in that case it is sufficient to apply a MAX aggregation function for each relevant field, partitioning on the "hour" field
WITH cte AS (
SELECT hour,
tableValue1,
0 AS tableValue3,
0 AS tableValue5
FROM table1
WHERE date = "2020-05-29" AND hour BETWEEN 0 AND 10
UNION ALL
SELECT hour,
0 AS tableValue1,
tableValue3,
0 AS tableValue5
FROM table2
WHERE date = "2020-05-29" AND hour BETWEEN 0 AND 10
UNION ALL
SELECT hour,
0 AS tableValue1,
0 AS tableValue3,
tableValue5
FROM table3
WHERE date = "2020-05-29" AND hour BETWEEN 0 AND 10
ORDER BY hour
)
SELECT hour,
MAX(tableValue1) AS tableValue1,
MAX(tableValue3) AS tableValue3,
MAX(tableValue5) AS tableValue5
FROM cte
GROUP BY hour
Check the demo here.
You must introduce empty columns in first query
SELECT hour , tableValue1, 0 tableValue3, 0 tableValue5 FROM table1 WHERE date = "2020-05-29" AND hour BETWEEN 0 AND 10
UNION ALL
SELECT hour , 0, tableValue3, 0 FROM table2 WHERE date = "2020-05-29" AND hour BETWEEN 0 AND 10
UNION ALL
SELECT hour , 0,0 tableValue5 FROM table3 WHERE date = "2020-05-29" AND hour BETWEEN 10 AND 10
We have an order table with fields as below e.g.
Timestamp PaymentID OrderID
341231231 6 1
342131231 12 2
123123123 18 3
123123122 14 4
123123143 12 5
433453454 6 6
445456456 18 7
What we want to do is get an output which will give us a month wise report on order count for each Payment Type but the payments are to be clubbed together for e.g. 6,8 PaymentID comes under type C so the count should be added for both in one
and all other PaymentID's come under type P
So the output what we want is like below.
Year Month C_Orders P_Orders
2015 01 0 4
2015 02 4 3
2015 03 1 0
2015 04 2 1
We tried 2 queries but has incorrect outputs
select SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),1,4) as year,SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),6,2) as month, co.payment_id, count(co.payment_id) as c_orders,co1.payment_id, count(co1.payment_id) as p_orders from
orders as co, orders as co1
WHERE co.payment_id in (6,18)
AND co1.payment_id not in (6,18)
GROUP BY year,month
AND
select SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),1,4) as year,SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),6,2) as month, 'COD', count(co.payment_id) as cod_orders
from
orders as co
WHERE co.timestamp >= UNIX_TIMESTAMP(CONVERT_TZ('2014-01-01 00:00:00','+00:00','+5:30')) AND co.timestamp <= UNIX_TIMESTAMP(CONVERT_TZ('2020-12-31 23:59:59','+00:00','+5:30')) AND co.is_parent_order = 'N' AND co.status IN ('C','G','E','P') AND co.payment_id in (6,18)
GROUP BY year,month
union
select SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),1,4) as year,SUBSTRING(CONVERT_TZ(FROM_UNIXTIME(co.timestamp),'+00:00','+5:30'),6,2) as month, 'PREPAID', count(co.payment_id) as prepaid_orders
from
orders as co
WHERE co.timestamp >= UNIX_TIMESTAMP(CONVERT_TZ('2014-01-01 00:00:00','+00:00','+5:30')) AND co.timestamp <= UNIX_TIMESTAMP(CONVERT_TZ('2020-12-31 23:59:59','+00:00','+5:30')) AND co.is_parent_order = 'N' AND co.status IN ('C','G','E','P') AND co.payment_id not in (6,18)
GROUP BY year,month
Use a case statement to only sum/count the values when a condition is met.
select year, month,
sum(case when payment_id in (6,18) then 1 else 0 end) as 'payment_id in (6,18)',
count(case when payment_id not in (6,18) then payment_id else null end) as 'payment_id not in (6,18)'
from table
group by 1,2
I want a query that can give result with sum of last 7 day look back.
I want output date and sum of last 7 day look back impressions for each date
e.g. I have a table tblFactImps with below data:
dateFact impressions id
2015-07-01 4022 30
2015-07-02 4021 33
2015-07-03 4011 34
2015-07-04 4029 35
2015-07-05 1023 39
2015-07-06 3023 92
2015-07-07 8027 66
2015-07-08 2024 89
I need output with 2 columns:
dateFact impressions_last_7
query I got:
select dateFact, sum(if(datediff(curdate(), dateFact)<=7, impressions,0)) impressions_last_7 from tblFactImps group by dateFact;
Thanks!
If your fact table is not too big, then a correlated subquery is a simple way to do what you want:
select i.dateFact,
(select sum(i2.impressions)
from tblFactImps i2
where i2.dateFact >= i.dateFact - interval 6 day
) as impressions_last_7
from tblFactImps i;
You can achieve this by LEFT OUTER JOINing the table with itself on a date range, and summing the impressions grouped by date, as follows:
SELECT
t1.dateFact,
SUM(t2.impressions) AS impressions_last_7
FROM
tblFactImps t1
LEFT OUTER JOIN
tblFactImps t2
ON
t2.dateFact BETWEEN
DATE_SUB(t1.dateFact, INTERVAL 6 DAY)
AND t1.dateFact
GROUP BY
t1.dateFact;
This should give you a sliding 7-day sum for each date in your table.
Assuming your dateFact column is indexed, this query should also be relatively fast.
I have a two tables that look like this
customer table
first last cust_id
John Doe 0
Jane Doe 1
ledger table
posted_date cust_id
2014-01-14 0
2014-01-20 0
2013-12-20 0
2013-12-20 1
2013-11-12 1
2013-11-10 1
I need to calculate the number of months where the customer posted a transaction at least once, this is being called CustomerMonths for the last 12 months. This means CustomerMonths for each cust_id would be between 0 and 12. So for this data I would want to see
cust_id CustomerMonths
0 2
1 2
This is because cust_id 0 was in at least once in Jan 2014 and at least once in Dec 2013.
Similarly, cust_id 1 was in at least once in Dec 2013 and at least once in Nov 2013.
For this example for cust_id 0:
2014-01-14,
2014-01-20 = 1 CustomerMonths
2013-12-20 = 1 CustomerMonths
so total CustomerMonths for last 12 months for cust_id 0 is 2.
I have this working for one month but not sure how to get this to work for the last 12 months. Although I'd settle for it working for the last two months. I think i could figure out the rest. Here's what I have.
select distinct
c.cust_id,
(case when count(lJan.posted_date) = 0 then 0 else
case when count(lJan.posted_date) > 0 then 1 end end) as CustomerMonths
from 'customer' c
left join 'ledger' lJan on (lJan.cust_id = c.cust_id and lJan.posted_date between '2014-01-01' and '2014-01-31')
group by c.cust_id
You need to count distinct months, so use count(distinct). The question is what is the argument. Try this:
select c.cust_id,
count(distinct year(l.posted_date) * 100 + month(l.posted_date)) as CustomerMonths
from customer c left join
ledger l
on l.cust_id = c.cust_id and
l.posted_date between '2013-01-01' and '2014-01-31'
group by c.cust_id;
Another way of writing the select:
select c.cust_id,
count(distinct date_format(l.posted_date, '%Y-%m')) as CustomerMonths
I have a query that involves searching database over a range of 30 days. Queries, both with correct output and wrong output are below:
CORRECT RESULTS:
SELECT
affiliates.member_id,
IFNULL( COUNT(orders.deal_id) , 0 ) AS deals_count,
IFNULL( SUM(orders.quantity) , 0 ) AS deals_quanity
FROM affiliates
LEFT JOIN deals ON affiliates.member_id = deals.member_id
LEFT JOIN orders ON deals.deal_id = orders.deal_id
LEFT JOIN customers_orders_link ON orders.order_id = customers_orders_link.order_id
AND DATE(customers_orders_link.datetime) BETWEEN '2011-06-01' AND '2011-07-01'
AND customers_orders_link.order_status = 'Delivered'
GROUP BY affiliates.member_id;
EXPECTED & RECEIVED: (Correct)
MemberID COUNT SUM
1 11 16
2 0 0
WRONG RESULTS:
//Notice the change in the date range
SELECT
affiliates.member_id,
IFNULL( COUNT(orders.deal_id) , 0 ) AS deals_count,
IFNULL( SUM(orders.quantity) , 0 ) AS deals_quanity
FROM affiliates
LEFT JOIN deals ON affiliates.member_id = deals.member_id
LEFT JOIN orders ON deals.deal_id = orders.deal_id
LEFT JOIN customers_orders_link ON orders.order_id = customers_orders_link.order_id
AND DATE(customers_orders_link.datetime) BETWEEN '2011-10-01' AND '2011-10-31'
AND customers_orders_link.order_status = 'Delivered'
GROUP BY affiliates.member_id
EXPECTED:
MemberID COUNT SUM
1 0 0
2 0 0
BUT I RECEIVE: (INCORRECT OUTPUT)
MemberID COUNT SUM
1 11 16
2 0 0
The first query is producing correct results whereas the second query is producing incorrect results. Even if I use a date in the past as the range, I still receive the same Incorrect Output. Its as if the query is completely ignoring the date range specification. So this case of ignoring the date range specification seems to be the problem.
How can I make the query "see" and "obey" the date range specification and actually receive the Expected Output for the 2nd query listed above?
EDIT 1:
//Table: Orders
order_id deal_id quantity price
1 1 2 40.00
1 2 1 15.00
2 1 1 20.00
3 9 1 5.00
4 1 2 40.00
4 9 2 10.00
5 1 1 20.00
5 9 1 5.00
6 1 2 40.00
6 9 2 10.00
7 1 1 20.00
8 11 1 1.00
//Table: customers_orders_link
order_id customer_id order_status datetime
1 4 Cancelled 2011-06-05 20:26:45
2 4 Delivered 2011-06-05 20:38:28
3 4 Pending Payment 2011-06-05 20:56:50
4 4 Pending Payment 2011-06-09 17:03:08
5 4 Pending Payment 2011-06-09 17:12:23
6 4 Pending Payment 2011-06-09 17:19:57
7 4 Pending Payment 2011-06-09 17:40:59
8 4 Pending Payment 2011-06-10 03:55:17
I solved it myself using a totally different method.
I don't know what your data looks like, but I suspect your LEFT JOIN customers_orders_link is to blame. If you only want to tally COUNT() and SUM() when the conditions of that table are met, it should be a standard JOIN in place of a LEFT JOIN.