I have an ordering system that can have multiple receipts related to one order. I recently ran into a query as follows that produced an undesirable result.
SELECT info FROM orders WHERE id IN (1, 2, 2) ORDER BY FIELD (id, 1, 2, 2);
Is there a way to return the row for order #2 twice? As of right now the query returns row one then row two as expected; however, in this particular instance returning row #2 twice is needed.
The tables are roughly as follows (I know it isnt totally valid MySQL, just for illustration):
CREATE TABLE orders (
id int(),
info VARCHAR(),
)
CREATE TABLE links (
orderid int(),
receiptid int()
)
CREATE TABLE receipts (
id int(),
otherinfo VARCHAR(),
)
If I'm understanding the situation correctly, you have two entries in the orders table
but orderId 2 is listed twice in the links table. If that is correct, then what you want is:
select o.info from orders o
inner join links l on o.id = l.orderid
If you need to return the row twice, then filtering in the where clause is not what you want. You can do this by filtering using a join:
SELECT o.info
FROM orders o join
(select 1 as id union all select 2 union all select 2
) ids
on o.id = ids.id
ORDER BY FIELD (o.id, 1, 2, 2);
Well, you coul make use of a UNION ALL
Something like
SELECT info FROM orders WHERE id IN (1, 2)
UNION ALL
SELECT info FROM orders WHERE id IN (2)
Related
The following query:
SELECT * FROM table WHERE id IN (1,2,3);
will return three records.
SELECT * FROM table WHERE id IN (1,2,1);
will return just two records (for Ids 1 and 2)
Is there a way for the result set to contain two records for Id 1 (and three in total)?
You could try creating a table for the ids you want to filter by. This would get you your desired results. I'm not sure if mysql supports CTE, but hopefully this is enough for you to get the idea.
WITH IDS
AS
(
SELECT 1 AS id
UNION ALL
SELECT 2 AS id
UNION ALL
SELECT 1 AS id
)
SELECT T.*
FROM T
JOIN IDS
ON T.id = IDS.id
So I have a situation where I have two tables. One is the base table (called _Keys in this example), with a unique primary key. Then there is another table with multiple rows of a data for each id in _Keys (this second table is Extra).
I need to select the largest value for each primary key in _Keys from Extra. I have made an SQLFiddle to model the problem here.
This is the query I'm currently using, but the issue is that it will only select one value for the Extra table, not one value per row.
Select * from _Keys
LEFT JOIN
(Select * from Extra ORDER BY value2 DESC LIMIT 1) as e
ON e.id = _Keys.id;
For my example SQL Fiddle I used this database schema:
CREATE TABLE _Keys(id int, value int);
INSERT INTO _Keys (id, value) VALUES (1, 5),(2, 3),(3, 4);
CREATE TABLE Extra(id int, value2 int);
INSERT INTO Extra (id, value2) VALUES (1, 3),(1, 1),(2, 4),(2, 6),(3, 3),(3, 5);
Basically my result is here. Only the first row from the _Keys table gets its data from the second table.
In MySQL, how can I achieve selecting one row from Extras for each row in _Keys?
I believe I understand what you are trying to do but I'm not sure.
You are getting NULL values because of the LIMIT, it only returns the first row. You also need to use GROUP BY.
To get the largest value, your can use MAX.
Try this.
SELECT * from _Keys
LEFT JOIN
(SELECT id, MAX(value2) AS value2 FROM Extra GROUP BY id) as e
ON e.id = _Keys.id;
Your joined table Select * from Extra ORDER BY value2 DESC LIMIT 1 will contain only one row because of LIMIT. Try this:
Select * from _Keys
LEFT JOIN
(Select id, max(value2) from Extra group by id) as e
ON e.id = _Keys.id;
You can try this query with better performance :
SELECT k.id, MAX(e.value2) AS value2
FROM _Keys k
INNER JOIN Extra e
ON (k.id = e.id)
GROUP BY k.id;
I currently use the following query which works perfectly:
SELECT * FROM `items` WHERE `id` IN
(SELECT `item_id` FROM `categories_items`
WHERE `category_id` IN (1, 2) GROUP BY `item_id`
HAVING COUNT(`item_id`) = 2);
It selects all the items that are in all the selected (checkboxes) categories.
The problem is that most items are in many categories and a few items are only in two categories and when I only check those two, I still get a list of hundreds of items, making it nearly impossible to find the items that are in few categories.
My first idea was to add an ORDER BY "number_of_total_categories_that_the_selected_item_is_in" ASC somewhere in the query, but since I even got help with the current one and there would probably be a lot of calculations/subqueries for it to work, I thought of an extra column in the items table that would hold the number of categories it's in!
Is it possible to add an effective ORDER BY clause to the query and if so, what would it look like?
Do you have any other ideas? Would "an inverted" foreign key solution work here? Not a chance, right? :p
If not, all I can think of is to manually update a category_count column in items whenever it's needed.
Edit: Table field that holds row count from another table looks interesting, but I have no idea whether it would work in MySQL.
You want to use join rather than in. The following query filters for items that only have the two categories you want. It also counts the total number of categories, which can be used for the order by:
SELECT i.*
FROM `items` i JOIN
(SELECT `item_id`, COUNT(*) as cnt
FROM `categories_items`
WHERE `category_id` IN (1, 2)
GROUP BY `item_id`
HAVING COUNT(DISTINCT CASE WHEN category_id IN (1, 2) THEN category_id END) = 2
) c
ON i.id = c.item_id
ORDER BY cnt ASC;
EDIT:
If you want to count all the categories, then get rid of the where. It is not really doing anything:
SELECT i.*
FROM `items` i JOIN
(SELECT `item_id`, COUNT(*) as cnt
FROM `categories_items`
GROUP BY `item_id`
HAVING COUNT(DISTINCT CASE WHEN category_id IN (1, 2) THEN category_id END) = 2
) c
ON i.id = c.item_id
ORDER BY cnt ASC;
I have a table where I store items and the time where they are relevant. For this question the following columns are relevant:
CREATE TABLE my_items
(
id INTEGER,
category INTEGER,
t DOUBLE
);
I want to select all items from a specific category (e.g. 1) and the sets of items that have a time within +- 5 (seconds) from these items.
I will probably do this with two types of queries in a script:
SELECT id,t from my_items where category=1;
then loop over the result set, using each result row's time as t_q1, and do a separate query:
SELECT id from my_items where t >= t_q1-5 AND t <= t_q1+5;
How can I do this in one query?
You can use a join. Take your subquery that selects all category 1 items, and join it with the original table on the condition that the time is within +/- five. It's possible that duplicate rows are returned, so you can group by id to avoid that:
SELECT t.*
FROM myTable t
JOIN (SELECT id, timeCol FROM myTable WHERE category = 1) t1
ON t.timeCol BETWEEN (t1.timeCol - 5) AND (t1.timeCol + 5)
OR t.id = t1.id
GROUP BY t.id;
I added the OR t.id = t1.id to make sure that the rows of category 1 are still included.
You can use a single query with all you criteria if there is only one table
SELECT id,t from my_items where category=1 AND t >= t_q1-5 AND t <= t_q1+5;
If there is two tables, use a right join on the timestamps table for performance.
select id
from my_items i,
(select min(t) min_t, max(t) max_t from my_items where category=1) i2
where i.category = 1 or
i.t between i2.min_t-5 and i2.max_t+5
I have collected informations from different sources about certain IDs that should match a single name. Some sources are more trustworthy than others in giving the correct name for a given ID.
I created a table (name, id, source_trustworthiness) and I want to get the most trustworthy name for each ID.
I tried
SELECT name, id, MAX( source_trustworthiness )
FROM table
GROUP BY id
this returns th highest trustworthiness available for each ID but with the first name it finds, regarless of its trustworthiness.
Is there a way I can get that right ?
Mysql has special functionality to help:
SELECT * FROM (
SELECT name, id, source_trustworthiness
FROM table
ORDER BY 3 DESC ) x
GROUP BY id
Although this wouldn't even execute in other databases (not naming all non-aggregate columns in the GROUP BY clause), with mysql it returns the first row encountered for each unique value of the grouped by columns. By ordering the rows greatest first, the first row for each id will be the most trustworthy.
Since this question is tagged mysql, this query is OK. Not only is it really simple, it's also quite fast.
SELECT a.*
FROM TableName a
INNER JOIN
(
SELECT id, MAX(source_trustworthiness) max_val
FROM TableName
GROUP BY ID
) b ON a.ID = b.ID AND
a.source_trustworthiness = b.max_val