Redirect row to another row mysql - mysql

id name redirect_id
1 .... NULL
2 ..... NULL
3 ..... 2
4 .... NULL
5 .... 1
i have this table. id is primary key. I want to get name of the row. However if it has a redirect_id, i want to get redirected id's name. Is there a possible way to do it in one sql query?
I know how to do it after fetching the result array. However it becomes so tangled if i do it that way. 1 sql query would be so good here. Thanks.
edit i need all redirected row not just redirrected name.

select ln.id
, COALESCE(ln2.name, ln.name)
from linkednames ln
left join linkednames ln2 on ln2.id = ln.redirect_id

If there is only one hop, then this is a simple join:
select t.id, (case when t.redirect_id is null then t.name else tr.name end) as name
from t left join
t tr
on t.redirect_id = tr.id;
If re-directs can have re-directs, you'll need more joins. MySQL does not have good support for hierarchical/recursive queries.

Related

Is there any SQL function or way to do this?

Is there any way we can do this in SQL?
Les say I have table Tablename_1 as below:
id
col1
1
data1
2
data2
3
data3
4
data4
5
data5
I want to check if the data I have in my where clause is present in the table or not
for example, where clause is as:
where id in (1,3,5,7);
Then I wish to output as below:
id
data_result
1
YES
3
YES
5
YES
7
NO
There are a few ways to do this.
One option is to provide your IDs as a table-valued constructor (VALUES() clause) instead of a WHERE clause. Then you can LEFT JOIN from this new "table" to create your result.
This is the MySql version (Postgresql needs to remove the row keywords):
select a.n, case when t1.id IS NULL then 'N' else 'Y' end as data_result
from (values row(1), row(3),row(5),row(7)) as a(n)
left join tablename_1 t1 on a.n = t1.id
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=028e5a984e5ed2969247e025bc8776be
You can also do this in a CTE via UNION:
WITH base as (
SELECT 1 as n UNION SELECT 3 UNION SELECT 5 UNION SELECT 7
)
SELECT base.n, case when t1.id IS NULL then 'N' else 'Y' end as data_result
FROM base
LEFT JOIN tablename_1 t1 on base.n = t1.id
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=ef2a88f6f89bf4101d7d651b4440ac28
This works the same in both databases, but as you can see means building a up lot more code per value in your list.
A final option is creating a dynamic numbers table. Then you can again LEFT JOIN these tables together to find out the Yes/No result for all possible values in the dynamic table and then still put your desired values in a WHERE clause to only show those results. The trick here is it requires you to have some idea of the possible scope for your values up front, and can make things a little slower if your guess is too far off.
Any of these could also be written to use an EXISTS() clause, which can often perform better. I just find the JOIN easier to write and reason about.
You could also use exists with the values approach from Joel
Something like
select v.*,
case when exists(select 1 from Tablename_1 as t where t.id=v.id) then
'Yes'
else
'No'
end
from (values (1),(3),(5),(7)) as v(id)
You can use ANY.
select Tablename_1.id,
case
when Tablename_1.id = ANY (ARRAY[1, 3,5,7])
then 'YES'
else 'NO' end
as data_result
from Tablename_1;
further reading: IN vs ANY operator in PostgreSQL

How to find latest rows in my msql using a specific column value

I have a table called Access_Status containing values such as below:
I would like the table to only return the Active users which are Tom Sullivan and John Martin.
It should NOT return the Active row for Marta Jenkins since Marta is actually suspended.
What's the best approach for this?
You can filter on the latest row per name with a correlated subquery, and ensure that the status is active:
select a.*
from access_status a
where
t.last_updated_date = (
select max(a1.last_updated_date)
from access_status a1
where a1.initial_id = a.initial_id
)
and a.access = 'ACTIVE'
For performance, you want an index on (intial_id, last_updated_date). Adding access as a last column the index might also help.
List of latest rows which are "ACTIVE":
SELECT ast1.*
FROM Access_Status ast1
LEFT JOIN Access_Status ast2 ON
ast1.Initial_ID = ast2.Initial_ID AND ast1.Last_Updated_Date < ast2.Last_Updated_date
WHERE ast2.Initial_ID IS NULL
AND ast1.Access = 'ACTIVE'
-- if the intent is to have latest rows that are NOT 'SUSPENDED'
-- AND ast1.Access <> 'SUSPENDED'
;
One of the way to get ACTIVE users:
select A.* from Access_Status A where A.Access = 'ACTIVE'
and A.Name not in (select Name from Access_Status WHERE Access != 'ACTIVE');
Thanks for all your attempts. Actually, I realize that I did not give enough information. There was an additional column end_date which will be null for all active users. So I can use ACCESS='ACTIVE' and end_date is null
This approach would help you for getting rows as your need
SELECT * FROM Access_Status GROUP BY Name WHERE Access="ACTIVE";

MySQL Get One Column Only Once

I have 2 MySQL tables in which I get data from in one query
"tables" table:
"checks" table:
The query I have been trying and the result of it:
SELECT tables.tableName, tables.tableRes, tables.tableResFor, checks.chkID, checks.chkDate, checks.chkStatus
FROM tables
LEFT JOIN checks ON tables.tableID=checks.chkTable
WHERE tables.tableID=3
ORDER BY checks.chkStatus DESC, checks.chkID ASC
Here are the problems
If there were no results from the query, I need the tableName column which comes out never null, so other columns can be null (works now)
I don't want to get the rows after first row, if the chkStatus column is 1 or 0 or null, shortly I need the rows with 2 on chkStatus, if the first row is 0, 1 or null, I don't need the other rows...
Thanks in advance, I have been working on this problem for more than 10 hours...
I need the other checks where chkStatus is 2 so, add the condition to the join
SELECT
tables.tableName
, tables.tableRes
, tables.tableResFor
, checks.chkID
, checks.chkDate
, checks.chkStatus
FROM tables
LEFT JOIN checks ON tables.tableID = checks.chkTable AND chkStatus = 2
WHERE tables.tableID = 3

SQL Update statement with 2 EXISTS clause

I am trying to update a value to be NULL where tracker_unique_id can be found in ab_split_tracker_unique_link where that ones ab_split_id can be found in a 3rd table ab_split_candidate.
I cant do it by giving it different values as they can be different from user to user on locals
UPDATE trustpilot_links SET `invite_after_enquiry` = NULL
WHERE EXISTS (
SELECT tracker_unique_id, ab_split_tracker_unique_link.ab_split_candidate_id
FROM ab_split_tracker_unique_link
WHERE EXISTS (
SELECT ab_split_candidate_id
FROM ab_split_candidate LEFT JOIN ab_split
ON ab_split_candidate.ab_split_id = ab_split.ab_split_id WHERE ab_split.reference="review_invite_after_enquiry"
)
);
Edit:
Table examples
Trustpilot Links
trustpilot_link_id | invite_after_enquiry | tracker_unique_id
1 1 123
2 0 1234
ab_split_tracker_unique_link
tracker_unique_id | ab_split_id
1234 32
Ab Split
ab_split_id | reference
32 review_invite_after_enquiry
I want to set values to null if there tracker cannot be found in table ab_split_tracker_unique_link with an ab_split_id that is equal to review_invite_after_enquiry in ab_split
Your subqueries are not related to their parent queries as they should be. Let's look at your inner-most query:
SELECT ab_split_candidate_id
FROM ab_split_candidate
LEFT JOIN ab_split ON ab_split_candidate.ab_split_id = ab_split.ab_split_id
WHERE ab_split.reference = 'review_invite_after_enquiry'
Well, first of all your WHERE clause dismisses outer-joined records, so this is essentially an INNER JOIN. But then: either there are such records or not. This has nothing to do with the record your are potentially updating, nor with the ab_split_tracker_unique_link you are looking up.
So either you are updating all records or none.
We would rather expect something like
UPDATE trustpilot_links tl
SET invite_after_enquiry = NULL
WHERE EXISTS
(
SELECT *
FROM ab_split_tracker_unique_link stul
WHERE stul.tracker_unique_id = tl.tracker_unique_id
AND ...
);
So add WHERE clauses that relate the subqueries to their parent queries.

Inner join A on B if B not empty, else A

Two tables:
prefix ( id, value )
---------------------
1 'hello'
2 'good afternoon'
3 'good night'
suffix ( id, value )
---------------------
1 'world'
3 'world'
I'd like to get
all from table prefix which can be joined on table suffix via id
result should look like:
prefix.id prefix.value
--------------------------
1 'hello'
3 'good night'
well - quite easy so far...
but if table suffix is empty I'd like everything from table prefix
without subselects/ctes or if.... and in one query fulfilling both conditions!
Is there any trick to get this done by some magic having-clause or tricky something else?
Just for testcases: SQL-fiddle
Well, there is a way, but I agree with others that your requirements make no (practical) sense.
Anyway, here you go:
Join the suffix table twice (each time with a left join). One join is on the id column, the other on an always true condition.
Group the results on the prefix columns you want in the output and at least one non-nullable column of the first instance of suffix.
In the HAVING clause, put a condition that the first suffix column is not null or the number of values of a non-nullable column in the second suffix instance is 0. (Obviously, every group will have the same number of rows, i.e. the count will be the same for every prefix row.)
This is the query:
SELECT prefix.id, prefix.value
FROM prefix
LEFT JOIN suffix ON prefix.id = suffix.id
LEFT JOIN suffix AS test ON 1=1
GROUP BY prefix.id, prefix.value, suffix.id
HAVING suffix.id IS NOT NULL OR COUNT(test.id) = 0;
And there's also a demo at SQL Fiddle.
You need an OR and NOT EXISTS:
SELECT
prefix.id, prefix.value
FROM
prefix
WHERE
EXISTS(SELECT 1 from suffix WHERE prefix.id=suffix.id)
OR NOT EXISTS(SELECT 1 FROM suffix)
Demo
I guess the answer is: no, you can't!
Or if you can: No, you shouldn't.