MySQL Select Additional Rows on Same Table - mysql

I am trying to return "parent" notes, where the from_person_id = 2. I would also like to return all of the "parent" note's child rows.
A "parent" note has a parent_note_id of 0.
A "child" note has a parent_note_id equal to its "parent" note's thread_note_id.
Both "parent" and "child" notes have the same thread_note_id.
Below is an example of 4 rows from the notes table. My query should be returning all 4 of these notes. Instead, it is only returning one.
mysql> SELECT * FROM notes WHERE note_id <= 4;
+---------+----------------+----------------+----------------+
| note_id | parent_note_id | thread_note_id | from_person_id |
+---------+----------------+----------------+----------------+
| 1 | 0 | 1 | 2 |
| 2 | 1 | 1 | 5 |
| 3 | 1 | 1 | 5 |
| 4 | 1 | 1 | 5 |
+---------+----------------+----------------+----------------+
4 rows in set (0.00 sec)
mysql> SELECT DISTINCT n.*
-> FROM notes as n
-> JOIN notes as n2 on n2.thread_note_id = n.thread_note_id
-> WHERE n.from_person_id = 2
-> AND n.parent_note_id = 0;
+---------+----------------+----------------+----------------+
| note_id | parent_note_id | thread_note_id | from_person_id |
+---------+----------------+----------------+----------------+
| 1 | 0 | 1 | 2 |
+---------+----------------+----------------+----------------+
1 row in set (0.00 sec)
I figured out a way to do it with two sub queries, but I am trying to avoid using sub queries in MySQL.
Anyone have a recommendation on how to get the query to return the parent note and all of its children using JOINs instead of Sub Queries?

I think you would do this as:
select n.*
from notes n
where n.parent_note_id = (select n2.note_id
from notes n2
where n2.from_person_id = 2
) or
n.from_person_id = 2;
For best performance, you want an index on notes(from_person_id, note_id).

Related

How to delete table rows that have not matches rows in second table

I have 2 tables in 1 database.
In the 2 tables there are several rows with the same contents.
table visitor
--------------------------
id | mytoken1 |
--------------------------
1 | token_abcd |
2 | token_efgh |
3 | token_ijkl |
4 | token_mnop |
--------------------------
table favorites
--------------------------
id | mytoken2 |
--------------------------
1 | token_abcd |
2 | token_efgh |
3 | token_ijkl |
4 | token_mnop |
5 | token_aaaa |
6 | token_bbbb |
7 | token_cccc |
8 | token_dddd |
--------------------------
How do I delete the mytoken2 column that is not in the mytoken1 column?
So in the example above I want to delete 4 rows of data, including:
token_aaaa
token_bbbb
token_cccc
token_dddd
I have tried to find a solution until I was dizzy but it has not been resolved, I hope someone will help me here ..
You can do using NOT IN
DELETE FROM favorites
WHERE token2 NOT IN (SELECT token1 FROM visitor)
You can use NOT EXISTS.
DELETE FROM favorites
WHERE NOT EXISTS (SELECT *
FROM visitor
WHERE visitor.mytoken1 = favorites.mytoken2);
JOIN also can be used here:
DELETE favorites.*
FROM favorites
LEFT JOIN visitor ON visitor.mytoken1 = favorites.mytoken2
WHERE visitor.id IS NULL;
Here you can test SQL query

mysql query, different performance between = and IN

why there is this difference of time execution between these two queries even if they retrieve the same amount of rows from the same table?
select cognome, nome, lingua, count(*)
from archivio.utente
where cognome in ('rossi','pecchia','pirono')
group by cognome, nome, lingua;
…
…
…
| Rossi | Mario | it | 1 |
| Pironi | Luigi | it | 1 |
| Pecchia | Fabio | it | 1 |
+----------------------+---------+--------+----------+
779 rows in set (0.03 sec)
select cognome, nome, lingua, count(*)
from archivio.utente
where nome='corrado'
group by cognome, nome, lingua;
…
…
…
| Rossi | Mario | it | 1 |
| Pironi | Luigi | it | 1 |
| Pecchia | Fabio | it | 1 |
+----------------------+---------+--------+----------+
737 rows in set (0.47 sec)
from mysql documentation :
https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-join-types
when we use in
Only rows that are in a given range are retrieved, using an index to select the rows.
The key column in the output row indicates which index is used.
when we use =
A full table scan is done for each combination of rows
So in one case all lines are retrieved and compared, in another case just a range.

Update tables based on NULL values in a derived table

I want to start out with this as a basis for my question that I may already know the answer to.
mysql> select a.i as AI, a.b as AB, b.i as BI, b.b as BB from a left join b using (i) union select a.i as AI, a.b as AB, b.i as BI, b.b as BB from b left join a using (i) where b.i = 5;
+------+----------+------+------+
| AI | AB | BI | BB |
+------+----------+------+------+
| 1 | Not NULL | 1 | 0 |
| 2 | Not NULL | 2 | 0 |
| 3 | Not NULL | 3 | 0 |
| 4 | Not NULL | 4 | 0 |
| 0 | Not NULL | NULL | NULL |
| NULL | NULL | 5 | 0 |
+------+----------+------+------+
6 rows in set (0.00 sec)
is there anyway the column AB where = 0 based on the fact that BI = NULL within a joined statement (as the row obviously doesn't exist), and then vice verse, update BB where AI = NULL?
My instinct is NO!!! for a couple of reasons which I am looking to debunk or verify.
for the same reason you cannot update a real table with a temptable algorithm based view. I do not believe that you can update a table from the output of a derived table (at least not in such a way as I am looking for).
probably the most important reason, you cannot update something based on something else that doesn't exist (or by definition may exist but is an unknown value) due to the fact that without the isnull() function you cannot compare null. That being said to use the isnull() function you would need to have a static table with NULL in it, however due to the fact that in this particular instance the NULL values are only in affect when the tables are joined together (due to the obvious reason that matching rows plainly just do not exist). To perform this effectively you would need to make the values real by creating a derived table... which leads us back to point number 1.
If this IS possible and someone knows how to accomplish this please let me know... also if so is it possible to update both of the values with one statement?
I was about half finished with this command when I realized that it may be useless based on knowledge and other research.
mysql> update a,b set b.b='n',a.b='n' where /*possibly a derived table here*/ = isnull((select i1 as 'a.i', i2 as 'b.i' from ((select a.i as i1, b.i as i2 from a left join b using (i) where isnull(b.i)=1) union (select a.i as i1, b.i as i2 from b left join a using (i) where isnull(a.i)=1) as derived1 where isnull(i1)) /*maybe an or statement of some kind and another two derived tables here equalling each other*/ ;
based on my statement it seems that I would need another derived table or 3 to complete the statement in any kind of complete fashion... although I am not confident that it can work based on my tries up till now.
Also its possible I have been at this for long enough that I am no longer thinking straight.
In any case I appreciate the help in advance (even a this is possible, here is the direction you need to go).
Let me know if I need to provide any further information.
P.S. I do not want to put too much emphasis on my unfinished MySQL statement as It may not even be in the direction that I need to be going... and thus confusing.
I have found a partial answer. Please let me know if anyone can extend this. also I had to reinstall everything due to upgrading to centos 7.
where:
mysql> (select b.i as '1',b.b as '2',a.i as '3',a.b as '4' from a left join b using (i)) union (select b.i as '1',b.b as '2',a.i as '3',a.b as '4' from b left join a using (i)) order by 1;
+------+--------------+------+--------------+
| 1 | 2 | 3 | 4 |
+------+--------------+------+--------------+
| NULL | NULL | 1 | 何もない |
| 2 | 何もない | 2 | 何もない |
| 3 | 何もない | 3 | 何もない |
| 4 | 何もない | 4 | 何もない |
| 5 | 何もない | 5 | 何もない |
| 6 | 何もない | NULL | NULL |
+------+--------------+------+--------------+
6 rows in set (0.00 sec)
The command would end up using the same join syntax:
mysql> update a right join b using (i) set b.b = 'ある' where isnull(a.i) or isnull(b.i);
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
In this case MySQL was able to properly locate the row in a that was missing a match in b and replace the data as specified.
mysql> (select b.i as '1',b.b as '2',a.i as '3',a.b as '4' from a left join b using (i)) union (select b.i as '1',b.b as '2',a.i as '3',a.b as '4' from b left join a using (i)) order by 1;
+------+--------------+------+--------------+
| 1 | 2 | 3 | 4 |
+------+--------------+------+--------------+
| NULL | NULL | 1 | 何もない |
| 2 | 何もない | 2 | 何もない |
| 3 | 何もない | 3 | 何もない |
| 4 | 何もない | 4 | 何もない |
| 5 | 何もない | 5 | 何もない |
| 6 | ある | NULL | NULL |
+------+--------------+------+--------------+
6 rows in set (0.00 sec)
I'm not sure if this is the best answer for this question or it can get more detailed yet. that is something I would have to do more research on. If this is the best answer please let me know. If not and someone knows the best answer please let me know.

Get related rows in the same table?

I'm struggling with this one. What I need is to Select a row AND other rows from the same table that are related. Here is an example of the table:
table
key | value | related
=================================
1 | omg | 0
2 | lol | 0
3 | rofl | 2
4 | barfoo | 0
5 | foo | 0
6 | bar | 0
...
20000 | haha | 2
(where the related "2" is the row key for "lol")
So in the case that i do (not simultaneously) either this:
SELECT * FROM table Where value='lol'
or this
SELECT * FROM table Where value='rofl'
or this
SELECT * FROM table Where value='haha'
it should return:
key | value | related
=================================
2 | lol | 0
3 | rofl | 2
20000 | haha | 2
Any ideas guys?
Thanks a lot!
try this:
Select * From table t
Where Exists
(Select * From Table
where value = #theValue
and valueKey in (t.ValueKey, t.related))

DBIx::Class: Only select results where has_many greater than zero

In our MySQL database, I have a third_party_accounts table and it has_many third_party_campaigns. However, not all accounts will have campaigns. What I would like to do in DBIx::Class is select only those accounts which have one or more campaigns. The simplest was I've found is as follows:
my $third_party_account_rs = $schema->resultset('ThirdPartyAccount');
my $with_campaigns_rs = $third_party_account_rs->search(
{ third_party_account_id => \'IS NOT NULL' },
{
join => 'third_party_campaigns',
group_by => 'me.id',
}
);
For the relevant database columns:
mysql> select id from third_party_accounts;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
3 rows in set (0.00 sec)
mysql> select id, third_party_account_id from third_party_campaigns;
+----+------------------------+
| id | third_party_account_id |
+----+------------------------+
| 1 | 1 |
| 2 | 2 |
| 3 | 1 |
+----+------------------------+
3 rows in set (0.00 sec)
This seems like such an obvious use case that I'm sure there's a simple way to do this, but I can't find it.
my $with_campaigns_rs =
$schema->resultset('ThirdPartyCampaigns')
->search_related('third_party_account');