Need a twin group by value - mysql

I have a query something like this,
SELECT SOME_ID, COUNT(ANOTHER_ID) AS WITHOUT_FILTER
from SOME_TABLE GROUP BY SOME_ID
this returns me
+------------+------------------+
| SOME_ID | WITHOUT_FILTER |
+------------+------------------+
| 1 | 40 |
| 2 | 30 |
+------------+------------------+
I have the same query with a condition which gives me filtered values.
SELECT SOME_ID, COUNT(ANOTHER_ID) AS WITH_FILTER
from SOME_TABLE WHERE SOME_COL > 10 GROUP BY SOME_ID
which returns obviously lesser values in the grouped_by section
+------------+----------------+
| SOME_ID | WITH_FILTER |
+------------+----------------+
| 1 | 20 |
| 2 | 15 |
+------------+----------------+
Now, I need a query to give me both the count values ie with condition and without condition in one single query. The result should be like this
+----------+----------------+---------------+
| SOME_ID | WITHOUT_FILTER | WITH_FILTER |
+----------+----------------+---------------+
| 1 | 40 | 20 |
| 2 | 30 | 15 |
+------------+--------------+---------------+
Please help me.

You can do this:
SELECT
SOME_ID,
COUNT(ANOTHER_ID) AS WITHOUT_FILTER
SUM(case when SOME_CONDITION then 1 else 0 end) AS WITH_FILTER
from SOME_TABLE GROUP BY SOME_ID

For learning purposes, here are my 2 cents. You can use COUNT on both fields:
SELECT SOME_ID,
COUNT(ANOTHER_ID) AS WITHOUT_FILTER
COUNT(case
when WHEN SOME_COL > 10 then ANOTHER_ID
else NULL
end) AS WITH_FILTER
from SOME_TABLE GROUP BY SOME_ID
The trick is that COUNT counts non-null values. This feature is ANSI SQL supported, BTW.

You can get a "COUNT, but only for the rows meeting a condition" effect by using IF() and SUM.
SELECT SOME_ID,
COUNT(ANOTHER_ID) AS WITHOUT_FILTER,
SUM(IF(SOME_COL > 10, 1, 0)) AS WITH_FILTER
FROM SOME_TABLE GROUP BY SOME_ID
(Note: This solution, and all the others except Adrian's, has a subtle problem if ANOTHER_ID is ever NULL. If that's the case, then Adrian's is the only one that is truly correct).

try CASE and SUM combined:
SELECT SOME_ID, COUNT(ANOTHER_ID) as WITHOUT_FILTER,
SUM(CASE WHEN SOME_COL > 10 THEN 1 else 0 END) as WITH_FILTER
from SOME_TABLE GROUP BY SOME_ID;

SELECT T1.SOME_ID,
COUNT(T1.ANOTHER_ID) AS WITH_FILTER,
COUNT(T2.ANOTHER_ID) AS WITHOUT_FILTER
FROM SOME_TABLE as T1,
SOME_TABLE as T2
WHERE
T1.SOME_ID=T2.SOME_ID
AND T2.SOME_COL > 10
GROUP BY T1.SOME_ID, T2.SOME_ID
Or you can do it with 2 views merging if your conditions become too touchy

Related

How can I create a column with incremented values from a column with cumulated values in MySQL?

Table1 contains a column with cumulated values (all positive integers):
id ValuesCum
1 5
2 8
3 20
I would like to write a statement that returns an extra column with the incremented values for each row. The output should read something like:
id ValuesCum ValuesInc
1 5 (5)
2 8 3
3 20 12
Does anyone have a solution for this?
If you are running MySQL 8.0, you can use window function lag() for this:
select
t.*,
ValuesCum - lag(ValuesCum, 1, 0) over(order by id) ValuesInc
from mytable t
In earlier versions, an alternative is a correlated subquery:
select
t.*,
ValuesCum - (
select coalesce(max(t1.ValuesCum), 0)
from mytable t1
where t1.id < t.id
) ValuesInc
from mytable t
You can use a correlated subquery to get the value of ValuesCum of the previous id:
select t.*,
t.ValuesCum -
coalesce((select ValuesCum from tablename where id < t.id order by id desc limit 1), 0) ValuesInc
from tablename t
See the demo.
Results:
| id | ValuesCum | ValuesInc |
| --- | --------- | --------- |
| 1 | 5 | 5 |
| 2 | 8 | 3 |
| 3 | 20 | 12 |

MySQL Select all values from 1st column that have specific value in 2nd column

I have a mysql table with 2 columns.
+---------+-----------+
| Barcode | StationID |
+---------+-----------+
| 89411 | 1 |
| 89411 | 2 |
| 89411 | 3 |
| 89412 | 1 |
| 89413 | 1 |
+---------+-----------+
I would like to select all valus from Barcode column which have StationID = 1 and do NOT have a StationID different than 1.
As shown in the picture Barcode 89411 appears three times with different StationID and should be excluded from the result.
Can you help me make a query?
Another approach is to use an EXISTS query:
SELECT t1.*
FROM yourTable t1
WHERE
t1.StationID = 1 AND
NOT EXISTS (SELECT 1 FROM yourTable t2
WHERE t1.Barcode = t2.Barcode AND t2.StationID <> 1);
Demo
Use aggregation function GROUP_CONCAT, and use HAVING clause to filter out those barcodes, which has only one StationID, that is '1':
SELECT barcode, GROUP_CONCAT(DISTINCT StationID) AS stations
FROM table_name
GROUP BY barcode
HAVING stations = '1';
Try this: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=641d334c5f9e57bbdde07e4f24365f88
select barcode from tablename
group by barcode
having sum(case when sanctionid=1 then 0 else 1 end)=0
output:
barcode
89412
89413

How to query avg for every past 7 days in sql, MySQL?

Say I have a dataset of :
|dateid | value |
|20150101 | 1 |
|20150102 | 2 |
|20150103 | 3.1 |
|20150104 | 4.3 |
|20150105 | 3.1 |
|20150106 | 1 |
|20150107 | 1 |
|20150108 | 1 |
|.... | |
|.... | ... |
|20151001 | 10.3|
I want to query the average of every past 7 days based on a date range.
say for dateid from 20150707 and 20150730, when I select row of 20150707, I also need the average value between 20150701 and 20150707( (1+2+3.1+4.3+1+1+1+1)/7) as well as the value for 20150707(1) like:
select dateid, value , avg(value) as avg_past_7 from mytable where dateid between 20150707 and 20150730GROUP BY every past_7days.
And when the records are less than 7 rows to count, the avg remains null.
That means if I only have records from 20150707-20150730 in the table, the past_7_day avg for 20150707/8/9/10/11/12 remains null.
Correlated sub-select:
select dateid, value, (select avg(value) from mytable t2
where t2.dateid between (DATE_SUB(date(t1.dateid),INTERVAL 6 day)+0)
and t1.dateid) as avg_past_7
from mytable t1
where dateid between 20150101 and 20150201 order by dateid;
Use Date_SUB With Interval of 7 Days
I solve the problem by :
select t1.dateid, t1.value, if(count(1)>=7,avg(t2.value),null)
from mytable t1 , mytable t2
where t2.dateid between DATE_SUB(date(t1.dateid),INTERVAL 6 day)+0 and t1.dateid and
t1.dateid between 20150105 and 20150201
group by t1.dateid ,t1.value
order by dateid;

Select the same column multiple times with MySQL

Assuming I have something like this :
MySQL Table
Date | Name | Val
22/11 | a | 1
22/11 | b | 2
22/11 | a | 3
22/11 | a | 4
23/11 | b | 1
23/11 | a | 2
23/11 | a | 3
23/11 | a | 5
I need a query to have on one column the sum of the values for each day when Name = 'a' and an other column for the sum of all the values (for each day too).
With my example, the result would be something like this :
Date | a.Total | Total
22/11 | 8 | 10
23/11 | 10 | 11
I tried something like this :
SELECT date, SUM(Val) AS a.Total, SUM(Val) AS Total FROM tbl1 Where Name = 'a'
The point is that I need to specify a WHERE clause to get the "a.total" values (WHERE Name = 'a') but I don't want it to be apply to get the total.
I also tried queries with Left Join but it didn't work.
Any help is much appreciated.
You should use GROUP BY and CASE inside of the first SUM()
SELECT date,
SUM( CASE WHEN Name='a'
THEN Val
ELSE 0
END) AS a_Total,
SUM(Val) AS Total
FROM tbl1
GROUP BY `Date`
SQLFiddle demo
This is a type of problem called cross-tabbing (see https://www.simple-talk.com/sql/t-sql-programming/creating-cross-tab-queries-and-pivot-tables-in-sql/)
What you're after is the use of a CASE statement to allow you to sum values only when a condition is met.
SELECT date, SUM(CASE WHEN Name='a' then Val end) AS a.Total, SUM(Val) AS Total FROM tbl1 GROUP BY date

MySQL: How to return only one row based on criteria within a resultset

I have the following table:
id | group | value
1 | 1 | 10
2 | 1 | 20
3 | 1 | 30
4 | 0 | 20
5 | 0 | 20
6 | 0 | 10
I want to return the highest value where the group is 1 (=30) and all of the values where the group is 0, into one resultset.
I have to do this in one statement, and I guess I should use an IF statement within a SELECT statement, but I can't work out how. Can anyone help to point me in the right direction?
(select max(value) from the_table where group = 1)
union
(select value from the_table where group = 0)
If (group +value) is unique, you can also do it without union (as proposed by Ray Toal)
SELECT a.value
FROM table1 a
WHERE a.`group`=0 or (a.`group`=1 AND a.value =
(SELECT MAX(value) FROM table1 b WHERE b.`group`=1))