My table:
|id |value|
| 1 | a |
| 1 | b |
| 1 | c |
| 2 | b |
| 3 | a |
| 3 | d |
| 3 | c |
I want to get result like this:
|id |
| 1 |
| 3 |
whose id contain a and c values. Please help me.
Aggregation is one simple approach:
SELECT id
FROM yourTable
WHERE value IN ('a', 'c')
GROUP BY id
HAVING MIN(value) <> MAX(value);
The HAVING clause asserts that there are two different values present in each matching group after the WHERE clause has filtered off all values other than a and c. If the HAVING clause fails, then it means that both a and c are not present.
Other approach:
select id
from yourtable
group by id
having sum(case when value in('a','c') then 1 else 0 end ) = 2;
Related
I am trying to join two tables with respect to the max values for the values column. I would like to produce the expected results as shown below based on the max value while joining
select * from order
-------------------------
| ID | value | Name |
-------------------------
| 1 | 23 | REM |
| 2 | 0 | SER |
| 3 | 13 | MH |
| 4 | 3 | MH |
| 5 | 1 | MP |
-------------------------
select * from product
-------------------------
| ID | value | Name |
-------------------------
| 1 | 2 | ABC |
| 2 | 2 | DEG |
| 3 | 17 | XYZ |
-------------------------
Desired result:
-------------------------
| ID | Value | Name |
-------------------------
| 1 | 23 | REM |
| 2 | 2 | DEG |
| 3 | 17 | XYZ |
| 4 | 3 | MH |
| 5 | 1 | MP |
-------------------------
I have tried something like below but it's not fetching the value (NAME) from other table
SELECT
MAX(IF(a.value >b.value , a.value ,b.value )) AS Value
from order a left join product b on a.ID= b.ID
Please suggest how to get the expected result from these two tables.
Below is for BigQuery Standard SQL
#standardsql
select as value array_agg(struct(id, value, name) order by value desc limit 1)[offset(0)]
from
(
select * from `project.dataset.order`
union all
select * from `project.dataset.product`
)
group by id
with output
You can do this using a full join:
select id,
(case when p.val is null or p.val < o.val then o.val else p.val end),
(case when p.val is null or p.val < o.val then o.name else p.name end)
from product p full join
order o
using (id);
I just find this the simplest way to think about the problem.
I would like to sort a table by "number" only if the type is A
| number | type |
|--------|------|
| 1 | A |
| 2 | B |
| 3 | B |
| 4 | A |
| 5 | A |
the request would give :
| number | type |
|--------|------|
| 1 | A |
| 4 | A |
| 5 | A |
| 2 | B |
| 3 | B |
The rows with "A" type are sorted then the "B" rows are listed (no matter the order)
Is it possible to do it without UNION?
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(number SERIAL PRIMARY KEY
,type CHAR(1) NOT NULL
);
INSERT INTO my_table VALUES
(1,'A'),
(2,'B'),
(3,'B'),
(4,'A'),
(5,'A');
SELECT * FROM my_table ORDER BY type,CASE WHEN type = 'A' THEN number ELSE RAND() END;
+--------+------+
| number | type |
+--------+------+
| 1 | A |
| 4 | A |
| 5 | A |
| 3 | B |
| 2 | B |
+--------+------+
ORDER BY type, number will work:
SELECT number, type
FROM Tablename
ORDER BY type, number
Demo on SQL Fiddle
Note: ORDER BY type, here by default it will ordering the type values by the ascending order. It is equal to ORDER BY type ASC. As per your need, you may use DESC or ASC.
A CASE statement can help.
For "B" rows 'no matter the order'. Does that mean original order has to be retained? In that case following query can help.
select * from TableName
order by type, CASE WHEN type='A' THEN number ELSE 0 END
If original order need not be retained, then ELSE RAND() as answered by Strawberry is good.
I have a dataset that resembles the following:
| ID | Match1 | Match2 | Key | Val1 |
| 1 | a | b | a | a |
| 2 | a | b | c | b |
| 3 | a | b | keep | c |
| 4 | a | a | a | d |
You'll see rows 1-3 have matching values in Match1 and Match2, and row 3 has "keep" in the Key column.
I'm trying to write a query that will drop rows 1 and 2 based on matching criteria, but keep row 3 because of the key provided. The resulting dataset would look as follows:
| ID | Match1 | Match2 | Key | Val1 |
| 3 | a | b | keep | c |
| 4 | a | a | a | d |
Any suggestions for how to make this work?
Let me guess that you want one row per match1/match2 combo, with preference for the "keep". If so:
select t.*
from t
where t.id = (select t2.id
from t t2
where t2.match1 = t.match1 and t2.match2 = t.match2
order by (key = 'keep') desc, -- highest preference for "keep"
id desc -- most recent id
limit 1
);
To handle NULLs you can use a NULL-safe comparison:
select t.*
from t
where t.id = (select t2.id
from t t2
where t2.match1 <=> t.match1 and t2.match2 <= >t.match2
order by (key = 'keep') desc, -- highest preference for "keep"
id desc -- most recent id
limit 1
);
i've a table like:
| ID | value |
| 0 | 5 |
| 1 | 2 |
| 0 | 1 |
| 1 | 6 |
| 2 | 3 |
| 2 | 8 |
| 1 | 2 |
| 0 | 1 |
| 2 | 4 |
I'm trying to take in my result only one row for id where value is the min of all the column, something like:
SELECT DISTINCT * FROM table WHERE MIN(table.value) = table.value
how can i solve? thanks!
EDIT:
My desired output is:
| ID | value |
| 0 | 1 | -> is the min of all the rows with id = 0
| 1 | 2 |
| 2 | 3 |
EDIT 2:
Something like:
SELECT DISTINCT *
FROM tableName AS A
WHERE value = (SELECT MIN(value) From tableName AS B WHERE A.ID=B.ID)
But tableName is (SELECT * FROM ...........).. how can i perform?
SELECT DISTINCT ID, Value
FROM tableName
WHERE value = (SELECT MIN(value) From tableName)
SQLFiddle Demo
follow-up question, what happens if there are same lowest value with different ID, what record will be shown?
How about this:
SELECT DISTINCT a.ID, a.value
FROM tableName AS a
WHERE a.value = (SELECT MIN(b.value)
FROM tableName AS b
WHERE a.id = b.id)
This is what you want
select id,min(value) from tableName group by id
I have a few groups of data. Each group has a some property field.
For example:
_________________________
| id | value | property |
--------------------------
| 1 | 2 | 3 |
--------------------------
| 2 | 2 | 3 |
--------------------------
| 3 | 2 | 3 |
--------------------------
| 4 | 2 | 4 |
-------------------------
| 5 | 2 | 4 |
--------------------------
| 6 | 2 | 4 |
--------------------------
How can I update two strings ordered by id ASC with property = 3, and 2 strings ordered by id ASC with property = 4 by one query?
I want to update 2 of 3 rows with property = 3 and update 2 of 3 rows with property = 4. For example: rows with id 1 and 2, and rows with id 4 and 5
i.e. i want update groups of data with different conditions by one query
You can do it using calculated rank field, e.g. -
SELECT p1.*, COUNT(*) rank FROM properties p1
LEFT JOIN properties p2
ON p2.property = p1.property AND p2.id <= p1.id
GROUP BY p1.property, p1.id
This query will return dataset with row-number by property:
+------+-------+----------+------+
| id | value | property | rank |
+------+-------+----------+------+
| 1 | 2 | 3 | 1 |
| 2 | 2 | 3 | 2 |
| 3 | 2 | 3 | 3 |
| 4 | 2 | 4 | 1 |
| 5 | 2 | 4 | 2 |
| 6 | 2 | 4 | 3 |
+------+-------+----------+------+
Then you should update records with rank < 3:
UPDATE properties p
JOIN (SELECT p1.*, COUNT(*) rank FROM properties p1
LEFT JOIN properties p2
ON p2.property = p1.property AND p2.id <= p1.id
GROUP BY p1.property, p1.id) r
ON p.id = r.id
SET p.value = 100 -- set new value here
WHERE r.rank < 3
Here's the solution, and see discussion following:
update
t,
(select GROUP_CONCAT(ids) as matching_ids from (
select
SUBSTRING_INDEX(GROUP_CONCAT(id order by id), ',', 2) AS ids
from
t
where
property in (3,4)
group by
property
) s1
) s2
set value=12345
where
FIND_IN_SET(id, matching_ids) > 0
;
To illustrate, and assuming your table is called t, and the initial state is:
root#mysql-5.1.51> select * from t;
+----+-------+----------+
| id | value | property |
+----+-------+----------+
| 1 | 2 | 3 |
| 2 | 2 | 3 |
| 3 | 2 | 3 |
| 4 | 2 | 4 |
| 5 | 2 | 4 |
| 6 | 2 | 4 |
+----+-------+----------+
The result of running this query is:
root#mysql-5.1.51> select * from t;
+----+-------+----------+
| id | value | property |
+----+-------+----------+
| 1 | 12345 | 3 |
| 2 | 12345 | 3 |
| 3 | 2 | 3 |
| 4 | 12345 | 4 |
| 5 | 12345 | 4 |
| 6 | 2 | 4 |
+----+-------+----------+
A brief explanation of the query:
I pick up the first two ids for each property using the SUBSTRING_INDEX(GROUP_CONCAT(id order by id), ',', 2) statement.
I combine the above using GROUP_CONCAT(ids) as matching_ids to get all valid ids.
Finally, I update all rows in the table where the id is within combined matching_ids text.
Notes:
You should verify your group_concat_max_len variable is long enough. Default is 1024. You most probably want to have this in the millions, anyhow (regardless of my answer).
The query is far from being optimal. It answers your question, but you can't have an optimal query here.
You are most probably better off with a transaction containing two or three queries.
Good luck!
I'm assuming you mean to limit your two updates to two rows each. You can use ORDER BY and LIMIT in your update statements:
UPDATE yourtable
SET property = 'new_value'
WHERE value=2 AND property = 4
ORDER BY id ASC LIMIT 2
UPDATE yourtable
SET property = 'new_value'
WHERE value=2 AND property = 3
ORDER BY id DESC LIMIT 2
Update:
To force this into one query, you would need to JOIN against a subquery which retrieves the ids to update via UNION. I think this is legal:
UPDATE yourtable
JOIN (
(SELECT id FROM yourtable WHERE value=2 AND property=4 ORDER BY id ASC LIMIT 2)
UNION ALL
(SELECT id FROM yourtable WHERE value=2 AND property=3 ORDER BY id DESC LIMIT 2)
) updaterows ON yourtable.id = updaterows.id
SET property = 'new value'