MySQL: Fetching non-null values using multiple joins - mysql

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

Related

MySQLi query only one type of result

I am trying to query all the results for only one type of message from the database:
Table:
ID List Content
1 8 This
2 8 That
3 9 Other
4 8 Last
There will be about 20,000 rows in this table, so I don't want to select them all and then sort through them if I don't have to. Basically, the List numbers will be changing, so I won't know what they are, but I only want to query results where List is the same.
It's a cron job script that will be removing these from the table after it's ran, so it doesn't matter what the List is, as long as each query returns all the same List.
What's the way of doing this straight from the MySQLi query without knowing what List is?
SELECT * FROM Table WHERE List = 8
You seem to want to select rows where list is duplicated. To get the rows with the most duplication, you can use:
select t.*
from table t join
(select list, count(*) as cnt
from table
group by list
order by count(*) desc
limit 1
) tt
on t.list = tt.list;
If you want any rows where list is duplicated, you can remove the having clause.
Here's a way using exists to select all rows where another row with the same List value exists.
select * from mytable a
where exists (
select 1 from mytable b
where b.List = a.List
and b.Id <> a.Id
)

Finding item and dependent set of items from the same mysql table in one query

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

UPDATE with nested query in PostgreSQL with unwanted results

Due to its geographic capabilities I'm migrating my database from MySQL to PostgreSQL/PostGIS, and SQL that used to be so trivial is now are becoming painfully slow to overcome.
In this case I use a nested query to obtain the results in two columns, having in 1st column an ID and in the 2nd a counting result and insert those results in table1.
EDIT: This is the original MySQL working code that I need to be working in PostgreSQL:
UPDATE table1 INNER JOIN (
SELECT id COUNT(*) AS cnt
FROM table2
GROUP BY id
) AS c ON c.id = table1.id
SET table1.cnt = c.cnt
The result is having all rows with the same counting result, that being the 1st counting result of the nested select.
In MySQL this would be solved easily.
How would this work in PostgreSQL?
Thank you!
UPDATE table1 dst
SET cnt = src.cnt
FROM (SELECT id, COUNT (*) AS cnt
FROM table2
GROUP BY id) as src
WHERE src.id = dst.id
;

Use select result for WHERE clause

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.

Mysql Select within IF condition

looking to perform a query that on a particular conditions gets the data from another table.
it like
select field1, field2.... IF(fieldX=3,select value from sub_table where cat_id = 3 order by id desc limit 0,1, NULL) from abc ;
The query within the if is valid.
I am used to with implementing if conditions without any issue but those were all for some static values or a field. But, this is the first time I am trying to get a select's result in if and unable to do it.
The case is because for some particular value of 'fieldX' I need to get a record from another table.
Regards
Junaid
wrap you inner select in ( )
IF(fieldX=3, (select value from sub_table where cat_id = 3 order by id desc limit 0,1), NULL)
why not use a left join and use fieldX=3 as a join condition? if fieldX is different from 3, sql fills the field with NULL
select a.field1, a.field2, sub.value
from abc a
left join
(
select value from sub_table
where cat_id = 3
limit 0,1
) sub
on a.fieldX = 3
or, if you do want to get all rows for the corresponding values (i see you have cat_id = 3 and fieldX = 3, so basically cat_id = fieldX), just use a simple join. no need to use complicated if constructs. sql was built to do fast and efficient joins:
select a.field1, a.field2, sub.value
from abc a
left join sub_table sub
on a.fieldX = sub.cat_id
note however, that the second query will return multiple rows, when there are more matches between fieldX and cat_id (non-unique cat_id)
you could do something like:
select fields... from sub_table st
where st.idSubTable in(
Select IF(fieldX=3
,(
select st.idSubTable from sub_table where cat_id = 3 order by id desc limit 0,1
),
NULL)
from abc);
it will solve your problem.