There is a table {id | date}. I want to select all rows where date > date from the given row.
Normally I would do it in two queries:
SELECT `date` FROM `mytable` WHERE `id`={id}; //get {date} from known {id}
and
SELECT * FROM `mytable` WHERE `date`> {date} //get the desired result
Is it possible to do it in one SQL query?
Thanks!
select * from mytable where date > (select date from mytable where id = {id})
This is a good candidate for a self-join.
SELECT o.*
FROM mytable t -- For every row from This table,
CROSS JOIN mytable o -- and for every row in the Other (see note #2) table
WHERE t.id <> o.id -- such that it is a different row
AND o.date > t.date -- with a date later
AND t.id = {id} -- than a specific row.
Notes:
Because > is used in the value comparison, the t.id <> o.id clause can be omitted. In any case, the query planner should figure this stuff out just fine.
The CROSS JOIN starts off a Cartesian product but the WHERE filters bring it back down quickly. In particular the t.id = {id} clause (assuming that id has a unique constraint) brings down the multiplicity to at most one output row for each input row in o.
Related
I'm running a query in MySQL with an INNER JOIN that has a LIMIT on the subquery
The problem is, that the LIMIT on the subquery is affecting the number of rows returned.
I want to select all rows from table 1 (tickets) where the last row in ticket_updates relevant (t.ticketnumber = tu.ticketnumber) was not numeric in column contact_name
SELECT t.*
FROM tickets t
JOIN
( SELECT ticketnumber
FROM ticket_updates
WHERE type = 'update'
AND concat('', contact_name * 1) <> contact_name
ORDER
BY sequence DESC
LIMIT 1
) tu
ON t.ticketnumber = tu.ticketnumber
WHERE t.status <> 'Completed'
AND LOWER(t.department) = 'support';
But the results shown just return the 1 row
There are multiple rows in ticket_updates that relate to each row in tickets based on tickets.ticketnumber =ticket_updates.ticketnumber`
the contact_name column can either be a string or integer. I picked up the concat('', contact_name * 1) <> contact_name from another SO Post which tells me whether the value is numeric or not.
So I want to pick up the latest row (ORDER BY sequence DESC) in ticket_updates for each row in tickets and see whether contact_name is not numeric
Your query selects one row because (as you concluded yourself) your subquery is limited to one result.
what you want is probably something similar to what can be found in this answer (I assumed that you want the entry with biggest value for sequence, if the contratry, change to MIN)
with a subquery (there should be an adaptation from the shortest more optimized query in the cited answer, but let's see if this one works first):
SELECT t.*
FROM tickets t
INNER JOIN ( SELECT ticketnumber, MAX(tu.sequence) AS maxSequence
FROM ticket_updates tu
WHERE tu.type = 'update' AND concat('', tu.contact_name * 1) <> tu.contact_name
GROUP BY ticketnumber ) tu2
ON (t.ticketnumber = tu2.ticketnumber)
WHERE t.status <> 'Completed'
AND LOWER(t.department) = 'support';
see it in action
I am running a few queries which I want to convert to a single query using joins
My first query is
1) SELECT * FROM ACT_TABLE1 where node='5bbcdded' order by Instance_ID desc;
The output of the above query is as below
ID Instance_ID NODE
2326600581 23266005612 5bbcdded1
2326524592 23265245712 5bbcdded2
2326523503 23265234213 5bbcdded3
2326523004 23265229614 5bbcdded4
2) Now, I grab topmost Instance_ID and run another select query as follows
SELECT * FROM ACT_TABLE2 where TOP_INST_ID = '23266005612';
Here, there might be a situation where select query returns a null value from above query. In that case, I grab second topmost Instance_ID and run same select query as follows
SELECT * FROM ACT_TABLE2 where TOP_INST_ID = '23265245712';
The output of the above query returns only single row as below
ID NEXT_ID TOP_INSTANCE_ID
232660056 232660056 232652457
3) Now, I grab topmost NEXT_ID and run another select query as follows
SELECT * FROM ACT_TABLE3 where NEXT_ID = '232660056';
The output of the above query returns only single row as below
ID EXEP_ID NEXT_ID
232660072 232660139 232660056
4) Now, I grab topmost EXEP_ID and run another select query as follows
SELECT field2 FROM ACT_TABLE4 where ID = '232660139';
The output of the above query returns field2 which is my final result
In other words, I want to pass node='5bbcdded' in my first table so that i can fetch value of field2 from my fourth table
You can do Inner Join between all the tables, using their relationships.
Then, employ multiple level Order By clauses starting from the first table (all in Descending order, since you want topmost from all the tables). We use LIMIT 1 to get the first row after sorting, which will be topmost.
Inner Join will ensure that any non-matching rows (null in the next table) will be ignored.
Try:
SELECT t4.field2
FROM ACT_TABLE1 AS t1
INNER JOIN ACT_TABLE2 AS t2 ON t2.TOP_INST_ID = t1.Instance_ID
INNER JOIN ACT_TABLE3 AS t3 ON t3.NEXT_ID = t2.NEXT_ID
INNER JOIN ACT_TABLE4 AS t4 ON t4.ID = t3.EXEP_ID
where t1.node = '5bbcdded'
ORDER BY t1.Instance_ID DESC, t2.NEXT_ID DESC, t3.EXEP_ID DESC
LIMIT 1
I found this here to delete records with min ID:
DELETE FROM Table WHERE id NOT IN (SELECT MIN(id) FROM Table GROUP BY FieldA)
However I don't want all the found dupes in the table to have the one with the lower ID removed, only a subset of them. I have other criteria for other dupes patterns. So I made my select to get the subset of records that have dupes AND other conditions where I then DO want the min ids removed:
Select min(Z),Max(Z),count(*) from Table
group by P,N
having count(*)>1 and Min(Z)!=Max(Z) and Min(Z)>0
I am unclear how to first get that subset of records and THEN remove the minID from the dupes in that subset
In MySQL use LEFT JOIN:
delete t
from table t left join
(Select min(Z), Max(Z), count(*)
from Table
group by P, N
having count(*) > 1 and Min(Z) <> Max(Z) and Min(Z) > 0
) tt
on t.? = tt.?
where tt.? is null;
It is unclear how the id is defined in your expression. It is also unclear whether the subquery generates the ids to keep or to delete. The version above assumes it is generating the ids to keep. (If it generates the ids to delete, then use inner join and get rid of the where clause.)
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 am updating my table setting a field named "status" based on the condition that the total number of distinct rows should be more than 10 and less than 13. The query is as follows:
update myTable set status='Established'
where id IN(select id, count(*) as c
from myTable
where year>=1996 and year<=2008
group by id
having count(distinct year)>=10 and count(distinct year)<=13)
The problem is, I'm getting error1241 that is "operand should contain 1 column"! Could you please advise how can I solve this? Thanks!
The result of the sub query must return only 1 column :
update myTable set status='Established'
where id IN(select id
from myTable
group by id
having count(distinct year)>=10 and count(distinct year)>=13)
In MySQL, an update with a join often performs better than an update with a subquery in the where clause.
This version might have better performance:
update myTable join
(select id, count(*) as c
from myTable
where year >= 1996 and year <= 2008
group by id
having count(distinct year) >= 10 and count(distinct year) <= 13
) filter
on myTable.id = filter.id
set status = 'Established';
I will also note that you have a table where a column called id is not unique among the rows. Typically, such a column would be a primary key, so the having clause would always fail (there would only be one row).
update myTable
set status='Established'
where id IN(select id from myTable
group by id
having count(distinct year)>=10
and count(distinct year)>=13)
You are using IN operator and then you inner query returns two columns id and count(*) it should return only one column back.