SQL: Nested queries based on values of a column - mysql

I have queried a table with the following query
select content_type_code_id
, price
, count(price) AS PRICECOUNT
from dbo.transaction_unrated
where transaction_date >= '2012/05/01'
and transaction_date < '2012/06/01'
and content_provider_code_id in (1)
group by content_type_code_id, price
ORDER BY price ASC
which produces the following result set
content_type_code_id price PRICECOUNT
1 -1.99 1
1 -0.99 1
1 0.99 178
1 1.99 786
But I want a result set like this:
content_type_code_id price Debits Credits
1 0.99 178 1
1 1.99 786 1
(Negative price as credit and positive price as debit)

try this one
select content_type_code_id
, ABS(price)
, count(IF(price >= 0,1,null)) AS debits,
, count(IF(price < 0,1,null)) AS credits,
from dbo.transaction_unrated
where transaction_date >= '2012/05/01'
and transaction_date < '2012/06/01'
and content_provider_code_id in (1)
group by content_type_code_id, ABS(price)
ORDER BY price ASC

Try this:
SELECT content_type_code_id
, price * -1
, COUNT(price) AS PRICECOUNT
, (
SELECT COUNT (deb.price)
FROM dbo.transaction_unrated deb
WHERE deb.transaction_date >= '2012/05/01'
AND deb.transaction_date < '2012/06/01'
AND deb.content_provider_code_id IN (1)
AND deb.price = ( dbo.transaction_unrated.price * -1 )
)
FROM dbo.transaction_unrated
WHERE transaction_date >= '2012/05/01'
AND transaction_date < '2012/06/01'
AND content_provider_code_id IN (1)
AND price < 0
GROUP BY content_type_code_id
, price
, 4
ORDER BY price ASC

Related

MySQL Select duplicities according date interval

I have table orders:
id
login_name
success
order_date
1
login1
0
2021-01-05
2
login2
0
2021-01-06
3
login3
0
2021-01-08
4
login1
1
2021-01-04
5
login2
0
2021-01-01
I need to select id, login_name with success=0 for which exist another order with order_date older or younger than 60 days.
The result should be:
1 - login1, 2 - login2, 5 - login2
I have this, but I think that is not a right way:
SELECT id, login_name, COUNT(*)
FROM orders
WHERE success=0
GROUP BY login_name
HAVING COUNT(*) > 1
You can use the EXISTS as follows:
SELECT id, login_name, COUNT(*)
FROM orders r
WHERE success=0
and exists
(select 1 from orders rr
where rr.login = r.login
and abs(datediff(rr.order_date, r.order_date)) <= 60
and rr.id <> r.id
)
If you want orders that appear within 60 days of each other, you can use lag() and lead():
select o.*
from (select o.*,
lag(order_date) over (partition by login_name order by order_date) as prev_order_date,
lead(order_date) over (partition by login_name order by order_date) as lead_order_date
from orders o
) o
where prev_order_date > dateadd(day, -60, order_date) or
next_order_date < dateadd(day, 60, order_date);

How to add a few restrictios to a query?

I have difficulty with syntax...
This is my query:
SELECT t.diapason,
Count(*) AS 'number_of_users'
FROM (SELECT CASE
WHEN amount < 200 THEN '0-200'
WHEN amount >= 200 THEN '200 +'
end AS diapason
FROM (SELECT Sum(amount) AS amount
FROM payments) p) t
GROUP BY t.diapason
ORDER BY number_of_users DESC;
But now I need to select only users which had activity.login_time between '2018-01-01' and'2018-01-12'.
So, I think I should use INNER JOIN and set period of time. Bu how?
My tables:
activity
user_id login_time
1 01.01.2018
2 01.01.2018
3 03.01.2018
4 30.02.2018
payments
user_id amount payment_time
1 50 10.12.2017
1 200 09.12.2017
2 40 08.08.2017
what should I change in my query to add activity.login_time?
Output for period 01.01.2018-12.01.2018
diapason number_of_users
0-200 2
200+ 1
I understand your question as this. You had 3 users (user_id=1,2,3) login in the period 01.01.2018-12.01.2018. Of those users, user_id 1 made 2 payments totalling 250, user_id 2 made 1 payment of 40, and user_id 3 made 0 payments so their total is 0. Hence there are 2 values in the range 0-200, and 1 in the range 200 +. If that is the correct understanding, this query will give you the desired results:
SELECT CASE
WHEN amount < 200 THEN '0-200'
WHEN amount >= 200 THEN '200 +'
END AS diapason,
COUNT(*) AS number_of_users
FROM (SELECT a.user_id, COALESCE(SUM(p.amount), 0) AS amount
FROM activity a
LEFT JOIN payments p ON p.user_id = a.user_id
WHERE a.login_time BETWEEN '01.01.2018' AND '12.01.2018'
GROUP BY a.user_id) p
GROUP BY diapason;
Output:
diapason number_of_users
0-200 2
200 + 1
SQLFiddle demo
Update
To add another row with the total number_of_users, just add WITH ROLLUP to the GROUP BY clause:
SELECT CASE
WHEN amount < 200 THEN '0-200'
WHEN amount >= 200 THEN '200 +'
END AS diapason,
COUNT(*) AS number_of_users
FROM (SELECT a.user_id, COALESCE(SUM(p.amount), 0) AS amount
FROM activity a
LEFT JOIN payments p ON p.user_id = a.user_id
WHERE a.login_time BETWEEN '01.01.2018' AND '12.01.2018'
GROUP BY a.user_id) p
GROUP BY diapason WITH ROLLUP
Output:
diapason number_of_users
0-200 2
200 + 1
(null) 3
In your application framework you can use the fact that the diapason value is NULL to output something like Total instead.
Updated SQLFiddle
You can also do the same in MySQL (see this SQLFiddle) by wrapping this query up as a subquery and using a COALESCE on the diapason column. In that case the output would be:
diapason number_of_users
0-200 2
200 + 1
Total 3
You add WHERE clause to filter.
SELECT t.diapason,
COUNT(*) AS 'number_of_users'
FROM (
SELECT
CASE
WHEN amount < 200 THEN '0-200'
WHEN amount >= 200 THEN '200 +'
END AS diapason
FROM (
SELECT payments.user_id, SUM(amount) AS amount
FROM payments
INNER JOIN activity ON payments.user_id = activity.user_idAND activity.login_time = payments.payment_time
WHERE activity.login_time BETWEEN '2018-01-10' AND '2018-01-12'
GROUP BY payments.user_id
) p
) t
GROUP BY t.diapason
ORDER BY number_of_users DESC;

Add to query in order to get total sum of previous results SQL

I currently have a query that provides the result set below, I now need to add to this query to provide a total at the bottom of all the sales. I am not sure how to do this.
Current query:
SELECT
product,
COUNT(OrderNumber) AS CountOf
FROM
orders
WHERE
STATUS = 'booking' AND
Date(OrderDate) <= CURDATE() AND
Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY)
GROUP BY
product
ORDER BY CountOf DESC
Current Resultset:
product| count
-----------------------
pd1 | 3
pd4 | 1
pd2 | 1
desired result set =
product| count
-----------------------
pd1 | 3
pd4 | 1
pd2 | 1
Total | 5
Maybe you can add a UNION, and a SELECT with total amount. Something like this:
SELECT
product,
COUNT(OrderNumber) AS CountOf
FROM
orders
WHERE
STATUS = 'booking' AND
Date(OrderDate) <= CURDATE() AND
Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY)
GROUP BY
product
UNION
SELECT 'Total', count(OrderNumber) AS CountOf
FROM orders
WHERE
STATUS = 'booking' AND
Date(OrderDate) <= CURDATE() AND
Date(OrderDate) > DATE_SUB(CURDATE(),INTERVAL 30 DAY)
ORDER BY CountOf DESC;
Try using an Inner join on the same table, the union did not work due to there being the incorrect amount of columns on each side.
The Initial select had 2 set columns, where the second select (after the union) did not.

MYSQL select info from sum within the query

this query works but pulls all results. I would like it to only pull results that are not 0.00 which is the totaldue. This is calculated within the query but I do not know how to exclude results with 0.00?
SELECT name,
SUM(IF(timeperiod='0',totalinv-paidtotal,0)) AS p0030,
SUM(IF(timeperiod='30',totalinv-paidtotal,0)) AS p3060,
SUM(IF(timeperiod='60',totalinv-paidtotal,0)) AS p6090,
SUM(IF(timeperiod='90',totalinv-paidtotal,0)) AS p9000,
SUM(totalinv)-SUM(paidtotal) AS totaldue
FROM
(
SELECT primary_key, name, timeperiod, totalinv, SUM(paidtotal) as paidtotal
FROM
(
SELECT
a.primary_key,
a_name AS name,
CAST(totalinv AS DECIMAL(10,2)) as totalinv,
CAST(IFNULL(amount,0) AS DECIMAL(10,2)) as paidtotal,
CASE
WHEN invoicedate > DATE_SUB(STR_TO_DATE($today,'%Y%m%d'),INTERVAL 29 DAY) THEN '0'
WHEN invoicedate > DATE_SUB(STR_TO_DATE($today,'%Y%m%d'),INTERVAL 59 DAY) AND invoicedate <= DATE_SUB(STR_TO_DATE($today,'%Y%m%d'),INTERVAL 29 DAY) THEN '30'
WHEN invoicedate > DATE_SUB(STR_TO_DATE($today,'%Y%m%d'),INTERVAL 89 DAY) AND invoicedate <= DATE_SUB(STR_TO_DATE($today,'%Y%m%d'),INTERVAL 29 DAY) THEN '60'
ELSE '90'
END AS timeperiod
FROM $mysql_billing a
LEFT OUTER JOIN $mysql_billing_dates b ON a.primary_key = b.id
WHERE $today >= invoicedate
AND $totaldue!='0.00'
AND void=''
) foo
GROUP BY primary_key, name, timeperiod
) bar
GROUP BY name
ORDER BY name ASC
You are just missing a HAVING at the very end:
....
GROUP BY name
HAVING totaldue != 0
ORDER BY name ASC
That will allow you to select on your calculated/grouped column.

MySQL: Using ORDER BY and UNION

Please take a look at the following query:
INSERT INTO product_filter (product_id,filter_id)
SELECT product_id,
(CASE WHEN price < 100 then 1
WHEN price >= 100 AND price < 500 then 2
WHEN price >= 500 AND price < 1000 then 3
WHEN price >= 1000 AND price < 1500 then 4
WHEN price >= 1500 AND price < 2000 then 5
WHEN price >= 2000 AND price < 2500 then 50
WHEN price >= 2500 AND price < 3000 then 6
ELSE 51 END) AS filter_id
FROM product_special
ORDER BY priority DESC, date_end DESC
LIMIT 1
UNION
SELECT product_id,
(CASE WHEN price < 100 then 1
WHEN price >= 100 AND price < 500 then 2
WHEN price >= 500 AND price < 1000 then 3
WHEN price >= 1000 AND price < 1500 then 4
WHEN price >= 1500 AND price < 2000 then 5
WHEN price >= 2000 AND price < 2500 then 50
WHEN price >= 2500 AND price < 3000 then 6
ELSE 51 END) AS filter_id
FROM product WHERE product_id not IN
(SELECT product_id FROM product_special)
This is what the query is supposed to do:
select all special prices from the product_special table and depending on the price, associate them to different price filters
every product can have multiple special prices, so just pick the one that has higher priority and will last longer
select all regular prices from the product table (only those that don't have special price in the product_special table) and depending on the price, associate them to different price filters
Error I'm receiving:
Error Code: 1221. Incorrect usage of UNION and ORDER BY
Sample Data sets:
Products
Specials
Any help is appreciated.
When you use UNION queries with LIMIT or ORDER BY for each separate query then you need to organize your queries using brackets like
(query 1 with limit order by )
UNION
(query 1 with limit order by )
Your above query can be written as to avoid this error
INSERT INTO product_filter (product_id,filter_id)
(
SELECT product_id,
(CASE WHEN price < 100 then 1
WHEN price >= 100 AND price < 500 then 2
WHEN price >= 500 AND price < 1000 then 3
WHEN price >= 1000 AND price < 1500 then 4
WHEN price >= 1500 AND price < 2000 then 5
WHEN price >= 2000 AND price < 2500 then 50
WHEN price >= 2500 AND price < 3000 then 6
ELSE 51 END) AS filter_id
FROM product_special
ORDER BY priority DESC, date_end DESC
LIMIT 1 )
UNION
(SELECT product_id,
(CASE WHEN price < 100 then 1
WHEN price >= 100 AND price < 500 then 2
WHEN price >= 500 AND price < 1000 then 3
WHEN price >= 1000 AND price < 1500 then 4
WHEN price >= 1500 AND price < 2000 then 5
WHEN price >= 2000 AND price < 2500 then 50
WHEN price >= 2500 AND price < 3000 then 6
ELSE 51 END) AS filter_id
FROM product WHERE product_id not IN
(SELECT product_id FROM product_special)
)
You need to use a sub-query for the ORDER BY and LIMIT in the first query.
Something like this:
INSERT INTO product_filter (product_id,filter_id)
SELECT * FROM
(SELECT product_id,
(CASE WHEN price < 100 then 1
WHEN price >= 100 AND price < 500 then 2
WHEN price >= 500 AND price < 1000 then 3
WHEN price >= 1000 AND price < 1500 then 4
WHEN price >= 1500 AND price < 2000 then 5
WHEN price >= 2000 AND price < 2500 then 50
WHEN price >= 2500 AND price < 3000 then 6
ELSE 51 END) AS filter_id
FROM product_special
ORDER BY priority DESC, date_end DESC
LIMIT 1) a
UNION
SELECT product_id,
(CASE WHEN price < 100 then 1
WHEN price >= 100 AND price < 500 then 2
WHEN price >= 500 AND price < 1000 then 3
WHEN price >= 1000 AND price < 1500 then 4
WHEN price >= 1500 AND price < 2000 then 5
WHEN price >= 2000 AND price < 2500 then 50
WHEN price >= 2500 AND price < 3000 then 6
ELSE 51 END) AS filter_id
FROM product WHERE product_id not IN
(SELECT product_id FROM product_special)
You should round brackets in order to use ORDER/LIMIT on individual queries
For example
(SELECT * FROM table1 WHERE ... ORDER BY field1 LIMIT 0, 1)
UNION
(SELECT * FROM table1 WHERE ...)
If you use Order BY outside brackets , it applies to UNIONED result