sql group by date gives same value everyday - mysql

So I want to group by days for statistics so I have data on each day (type 1 is bought and 0 is sold) but the query gives me the same result everyday and that is not correct can someone help me with this code?
SELECT
DATE(from_unixtime(credit_transaction_time)) AS data_date,
total_spend AS credits_spend,
total_bought AS credits_bought
FROM credit_transactions
JOIN (SELECT SUM(`credit_transaction_amount`) AS total_spend FROM credit_transactions WHERE `credit_transaction_type` = 0 GROUP BY DATE(from_unixtime(credit_transaction_time))) AS spend
JOIN (SELECT SUM(`credit_transaction_amount`) AS total_bought FROM credit_transactions WHERE `credit_transaction_type` = 1 GROUP BY DATE(from_unixtime(credit_transaction_time))) AS bought
GROUP BY DATE(from_unixtime(credit_transaction_time))

Use conditional aggregation:
SELECT DATE(from_unixtime(credit_transaction_time)) AS data_date,
SUM(CASE WHEN credit_transaction_type = 0 THEN credit_transaction_amount ELSE 0 END) as credits_spend,
SUM(CASE WHEN credit_transaction_type = 1 THEN credit_transaction_amount ELSE 0 END) as credits_bought
FROM credit_transactions
GROUP BY DATE(from_unixtime(credit_transaction_time));
Your query doesn't work because you don't have an ON condition. In most databases, this would result in a syntax error, but MySQL allows this syntax.

Related

MySQL - join/group concat returning too many items

I've got a simple query which brings up wins, draws and losses in a head-to-head matches table.
SELECT
SUM(CASE WHEN score_w > score_m THEN 1 ELSE 0 END) AS wins_w,
SUM(CASE WHEN score_m > score_w THEN 1 ELSE 0 END) AS wins_m,
SUM(CASE WHEN score_w = score_m THEN 1 ELSE 0 END) AS draws
FROM 6dos7me3xn8
All is well. I get a single row, with the data I need as columns.
Now I want to also pull out a group concat'd list of the most recent three match dates. I tried:
SELECT
SUM(CASE WHEN mn.score_w, 0) > mn.score_m THEN 1 ELSE 0 END) AS wins_w,
SUM(CASE WHEN mn.score_m > mn.score_w THEN 1 ELSE 0 END) AS wins_m,
SUM(CASE WHEN mn.score_w = mn.score_m THEN 1 ELSE 0 END) AS draws,
GROUP_CONCAT(jn.date) AS recent
FROM 6dos7me3xn8 mn
JOIN (SELECT date FROM 6dos7me3xn8 ORDER BY date DESC LIMIT 3) jn
...but the LIMIT is having no effect, seemingly - I get all of the dates group concat'd, not just 3.
I also tried removing the JOIN and replacing the GROUP_CONCAT with
GROUP_CONCAT((SELECT date FROM 6dos7me3xn8 ORDER BY date DESC LIMIT 3)) AS recent
...but that errors with 'Subquery returns more than 1 row.'
I'm sure it's something simple, but what am I doing wrong?
If you are running MySQL 8.0, you can do this with window functions:
select
sum(score_w > score_m) as wins_w,
sum(score_m > score_w) as wins_m,
sum(score_w = score_m) as draws,
group_concat(case when rn <= 3 then date end) as recent
from (
select t.*, row_number() over(order by date desc) rn
from `6dos7me3xn8` t
) t
The subquery ranks records by descending date; we can then use that information in the outer query. Note that you don't need the case expressions: MySQL evaluates true/false conditions as 1/0 in numeric contet.
In earlier versions, the simpler approach is probably a row-limiting subquery:
select
sum(score_w > score_m) as wins_w,
sum(score_m > score_w) as wins_m,
sum(score_w = score_m) as draws,
(select group_concat(date) from (select date from `6dos7me3xn8` order by date desc limit 3) t) as recent
from `6dos7me3xn8`
You are doing a cross join. TO get the most recent three dates, you can use:
FROM (SELECT mn.*, DENSE_RANK() OVER (ORDER BY date desc) as seqnum
FROM 6dos7me3xn8 mn
) mn
WHERE seqnum <= 3
You have no ON clause to specify the relationship between the subquery and the table you're joining it to. So you get a full cross product.
You also need ORDER BY to make it return the 3 most recent dates, not any 3 dates.
SELECT
SUM(CASE WHEN mn.score_w, 0) > mn.score_m THEN 1 ELSE 0 END) AS wins_w,
SUM(CASE WHEN mn.score_m > mn.score_w THEN 1 ELSE 0 END) AS wins_m,
SUM(CASE WHEN mn.score_w = mn.score_m THEN 1 ELSE 0 END) AS draws,
GROUP_CONCAT(jn.date) AS recent
FROM 6dos7me3xn8 mn
JOIN (
SELECT DISTINCT date
FROM 6dos7me3xn8
ORDER BY date DESC
LIMIT 3
) jn ON jn.date = mn.date

SQL query to DQL

I have a big query and I want to add a subquery to get the availability of accommodation-rooms.
This is the SQL subquery:
,(SELECT (CASE WHEN count(_days) > 0 THEN 'yes' ELSE 'No' END) as available
FROM
(
SELECT count(rtd.room_type_id) as _days
FROM room_type_day as rtd
WHERE rtd.date IN ('2018-06-20', '2018-06-21', '2018-06-22')
GROUP BY rtd.room_type_id
HAVING COUNT(rtd.room_type_id) = 3
) as sub) as availability
Can anyone tell me how to convert this SQL in DQL?
Thak you
EDIT
I try with this changes but the response is null every time:
,(SELECT (CASE WHEN count(rtd.roomType) > 0 THEN 'yes' ELSE 'no' END)
FROM AppBundle:RoomTypeDayCancelationConditionAccommodation as RTDCCA2
LEFT JOIN RTDCCA2.roomTypeDay as rtd
WHERE rtd.date IN ('2018-06-20', '2018-06-21', '2018-06-22')
GROUP BY rtd.roomType
HAVING COUNT(rtd.roomType) = 3
) as disponible

Get all users who placed requests in last three years

I would like to get all the list of users who placed requests in the last three years.
Requests( request_id, request_day, user_id, userprofile_id )
Am I doing it right?
SELECT user_id
FROM requests
WHERE EXTRACT(YEAR FROM request_day) IN ( 2014,2015,2016 )
GROUP BY user_id
HAVING COUNT(*) = 3;
Your current approach is almost correct. All you need to do is to count by the distinct number of years:
SELECT user_id
FROM requests
WHERE YEAR(request_day) IN (2014, 2015, 2016)
GROUP BY user_id
HAVING COUNT(DISTINCT YEAR(request_day)) = 3;
If the DISTINCT count of years is 3, then it implies that a user has all three of the years in your WHERE IN clause.
Note that another way to do this would be conditional aggregation:
SELECT user_id
FROM requests
GROUP BY user_id
HAVING SUM(CASE WHEN YEAR(request_day) = 2014 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN YEAR(request_day) = 2015 THEN 1 ELSE 0 END) > 0 AND
SUM(CASE WHEN YEAR(request_day) = 2016 THEN 1 ELSE 0 END) > 0
This approach would scale better if your query were to get more complex.

How do I calculate the difference of two alias for sorting

Considering the following code:
SELECT SUM(w.valor),
SUM(CASE WHEN w.tipo = '+' THEN w.valor ELSE 0 END) AS total_credit,
SUM(CASE WHEN w.tipo = '-' THEN w.valor ELSE 0 END) AS total_debit,
w.clientUNIQUE,
c.client as cclient
FROM wallet AS w
LEFT JOIN clients AS c ON w.clientUNIQUE = c.clientUNIQUE
WHERE w.status='V'
GROUP BY w.clientUNIQUE
ORDER BY total_credit-total_debit
I'm trying to calculate the difference of two aliased calculated values for sorting purposes, but I'm getting the following error:
Reference 'total_credit' not supported (reference to group function)
What am I doing wrong and how can I order results by using the difference value between the two aliases?
You can't refer to columns by their alias in the same select expression, so there are 2 options...
Repeat the expressions in the order by (yuk):
ORDER BY
SUM(CASE WHEN w.tipo = '+' THEN w.valor ELSE 0 END) AS total_credit -
SUM(CASE WHEN w.tipo = '-' THEN w.valor ELSE 0 END) AS total_debit
Or easier on the brain and easier to maintain (DRY), order via a sub query:
select * from (
<your query without the ORDER BY>
) q
ORDER BY total_credit - total_debit

Difference between these two mysql queries

I want to know the difference between these two queries: The first query is giving me all the records and its just fine.
Select * from table1 where tender_id='$tender_id' group by supplier_name
But in the following query I have added a sum(case), but I am not getting the desired output. The first query is showing all the records, but the second query is not showing all the records. What mistake am I making?
select cs.*, tender_id,
SUM(CASE WHEN ifmain = 'Yes' THEN total_inr ELSE 0 END) AS maintotal,
SUM(CASE WHEN ifmain = 'No' THEN total_inr ELSE 0 END) AS subtotal
from table1 cs
where cs.tender_id='$tender_id'
group by cs.supplier_name
I want to know if the second query can display all the records with conditions (tender_id)? or its iterating more?
In standard SQL, a query that includes a GROUP BY clause cannot refer
to nonaggregated columns in the select list that are not named in the
GROUP BY clause.
see (for example) https://dev.mysql.com/doc/refman/5.0/en/group-by-handling.html
MySQL has a an unfortunate (and in my opinion incorrect) default behavior when using a GROUP BY clause. This query would NOT be valid in most SQL databases:
Select * from table1 where tender_id='$tender_id' group by supplier_name
and it would not be valid in MySQL either if the ONLY_FULL_GROUP_BY SQL mode has been enabled.
I strongly recommend you treat all queries using GROUP BY as needing ALL non-aggregating columns in that clause. e.g.
select
cs.supplier_name
, SUM(CASE WHEN ifmain = 'Yes' THEN total_inr ELSE 0 END) AS maintotal
, SUM(CASE WHEN ifmain = 'No' THEN total_inr ELSE 0 END) AS subtotal
from table1 cs
where cs.tender_id='$tender_id'
group by
cs.supplier_name
If you need extra columns then e.g.
select
cs.supplier_name
, tender_id
, SUM(CASE WHEN ifmain = 'Yes' THEN total_inr ELSE 0 END) AS maintotal
, SUM(CASE WHEN ifmain = 'No' THEN total_inr ELSE 0 END) AS subtotal
from table1 cs
where cs.tender_id='$tender_id'
group by
cs.supplier_name
, tender_id
and so on. Of course as you include more columns in the group by clause you may increase the number of rows produced, but that is how GROUP BY should work.