How to aggregate this simple SQL? - mysql

I have a table like this:
ID Value Key
0 ValA 0
1 ValB 0
2 ValC 1
4 ValD 0
5 ValE 1
Apart from the table itself, I am also interested in the first ID with Key==1. I could use the following query to find it:
SELECT Key FROM MyTable WHERE Key=1 ORDER BY ID ASC LIMIT 1
Now, I'd like to combine the query to a regular SELECT, so that I have all the aggregated information in one go.
My following attempt failed, I tried:
SELECT
ID,
Value,
Key,
(SELECT Key FROM MyTable WHERE Key=1 ORDER BY ID ASC LIMIT 1 AS FirstKeyIs1)
FROM MyTable
How should I rewrite my query? The expected behaviour would have FirstKeyIs1 be 2. The goal is eventually filter out the IDs with a key property before 2.
ID Value Key FirstKeyIs1
0 ValA 0 2
1 ValB 0 2
2 ValC 1 2
4 ValD 0 2
5 ValE 1 2

If your database supports window functions, you can do:
select
t.*,
min(case when key = 1 then id end) over() firstKeyIs1
from mytable t
Otherwise, your approach using a subquery is OK. You just need to move the column alias out of the subquery - and presumably, you want to return the id rather than the key:
select
t.*,
(select id from mytable where key = 1 order by id limit 1) firstKeyIs1
from mytable
Or you can use aggregation in the subquery:
select
t.*,
(select min(id) from mytable where key = 1) firstKeyIs1
from mytable

Related

How can I get all affected row ids in mysql group by sentence?

I am doing a selection using GROUP BY, so I get a lot of different rows. What I need is to UPDATE the status field of each row affected by the SELECT query, but it is grouped... so I don't know all the ids, just the MAX(id).
This is the select query:
SELECT d.*, n.* FROM
(SELECT MAX(id) as id, MAX(datetime) as datetime, COUNT(DISTINCT content) as total FROM user_notifications
WHERE id_user
GROUP BY id_ref, type
ORDER BY datetime DESC) d
JOIN user_notifications n USING (id)
Edit:
Simple example, this is the table
id user content status
1 1 aaa 0
2 1 aaa 0
3 1 bbb 0
4 2 aaa 0
5 3 bbb 0
this is the query
select max(id), user, content from table where user=1 group by content
this is the result
id user content
2 1 aaa
3 1 bbb
in this query in fact sql internally select all user=1 (id= 1, 2, 3) and then the query is grouped, showing just two rows.
So, I want to update all ids involved in the query (id= 1 , 2 and 3)
Based on your example, you need the result exact to this query:
select id from `table` where user = 1;
But by using the query you provided which groups record by content
select max(id), user, content from `table` where user = 1 group by content
So, in such case you can join same table with derived table:
select id from `table` as t
join (select max(id), user, content from `table` where user = 1 group by content) as dt
on dt.content = t.content and dt.user = t.user;
This query is now equivalent to first straight forward query.

MySQL - SELECT a single value from two optional records based on a query param value

Here is my simplified scenario.
I have DB records in 'store_config' table:
ID store_id value
1 0 val1
2 10 val2
3 7 val3
4 99 val4
All records are optional - may or may not exist.
store_id column is unique.
I want to run a query:
WHERE store_id=?
So that:
The query should return a value matching the store_id from the query param if it exists, otherwise return value matching store_id 0 if it exists.
storeId=0 record is considered to be a default value and returned only if there is no existing record for the supplied storeId query param. That's the logic behind it.
You can use order by and limit:
select t.*
from t
where store_id in (#store_id, 0)
order by store_id desc
limit 1;
This assumes (as implied by your question) that there is only one row in the table for each store id. If that is not the case, you might want a more complicated version:
select t.*
from t
where store_id = #store_id
union all
select t.*
from t
where store_id = 0 and
not exists (select 1 from t t2 where t2.store_id = #store_id);
Here is one approach using a LIMIT trick:
SELECT ID, store_id, `value`
FROM store_config
WHERE store_id IN (0, 10)
ORDER BY store_id DESC
LIMIT 1;
The trick here is that if ID=10 is present, then its record would be the one retained. If ID=10 is not present, but ID=0 is present, then this record would be retained. Otherwise, the result set would be empty.
Please try this.
SELECT (IFNULL((SELECT store_id FROM #tbl Where id = #store_id LIMIT 1),0))

Count users and groups totals in one query

I am super new to access and having difficulty with a query. My table (tblpacks) is the following:
id user_id group_id quota_id
1 1 1 1
2 1 2 1
3 2 1 1
4 3 1 1
Ideally, what I now is to get hte number of unique users and groups for quota_id=1
The result will be:
total_users = 3
total_groups = 2
If you only wanted to count one field, there would by a simple solution, but since you want to count 2 separate fields, you in fact need at least 2 separate queries.
My answer is to use a UNION query as the source for counting. This UNION query returns the distinct user_id values (with Null as group_id) and the distinct group_id values (with Null as user_id). I omitted the DISTINCT keyword, because UNION (without ALL) does a DISTINCT query automatically. As the datatypes where not recognized correctly when using a constant Null field in the first SELECT statement of the UNION query, I added a third SELECT statement as the first one, which selects both fields from the table but returns no records:
SELECT Count(user_id) AS total_users, Count(group_id) AS total_groups
FROM (
SELECT user_id, group_id FROM tblpacks WHERE Yes=No
UNION
SELECT user_id, Null FROM tblpacks WHERE quota_id=1
UNION
SELECT Null, group_id FROM tblpacks WHERE quota_id=1
) AS qsub;

Mysql SELECT first row with value found or last row if no value

I would like to select row where first value found or last row if no value found.
id | customer | default_address
--------------------------------
1 John 0
2 Will 0
3 David null
4 Joe 0
In this case, i would like to have row with id = 4 because there's no default_address with value 1.
id | customer | default_address
--------------------------------
1 John 0
2 Will 1
3 David null
4 Joe 0
In this case, i need row 2 because i need default_address with value 1.
Default address can have values 0,1 and null.
Not so fancy, but I guess this should work and run pretty fast
select * from
(
(select * from your_table where default_address = 1 order by id limit 1)
union all
(select * from your_table order by id desc limit 1)
) tmp
limit 1
SQLFiddle demo
You can achieve this with a single query with conditional ordering using CASE EXPRESSION:
SELECT * FROM YourTable t
ORDER BY CASE WHEN t.default_address = 1 THEN t.id ELSE 999999999 end ASC,
t.id DESC
LIMIT 1;
This way, IF there is a record with default_address = 1 it will be ordered first, if not, the last ID will be ordered first, and then it will pick the first one using LIMIT 1.
Note that I used the value 999999999 in the case so it will choose the first one in case there is more then 1 row with default_address = 1, this number just have to be larger then your biggest ID in the table in order for this to work properly.
You can use this Sub-Query.
SELECT * FROM(
(SELECT * FROM your_table WHERE default_address = 1 ORDER BY id LIMIT 1)
UNION ALL
(SELECT * FROM your_table ORDER BY id DESC limit 1)
) tmp
limit 1

how to find the number of consecutive repeats

So I'm trying to write a mysql script to find the number of consecutive repeats in 'value' column of this table.
id value result
-- ----- ------
1 1 0
2 1 1
3 2 0
4 3 0
5 3 1
So in this case I want get the value 2
Get the next value using user variables,
GROUP so consecutive values more than 2 are not counted again,put all in a subquery,and use a simple CASE to increment the value you need in case value=next value.Add salt and pepper.
SELECT SUM(CASE WHEN y.value=y.next_value THEN #var+1 ELSE #var END) consecIds
FROM
(SELECT t.id, t.value, next_id, n.value next_value
FROM
(
SELECT t.id, t.value,
(
SELECT id
FROM table1
WHERE id > t.id
ORDER BY id
LIMIT 1
) next_id
FROM table1 t,(SELECT #var:=0)x
) t LEFT JOIN table1 n
ON t.next_id = n.id
GROUP BY t.value,n.value)y
FIDDLE
SELECT COUNT(DISTINCT column_name) FROM table_name;
DISTINCT will erase duplicated repetitions from specified column in result.
COUNT will count the rows in result.
The COUNT(DISTINCT column_name) function returns the number of distinct values of the specified column.