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

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');

Related

Using code to increment values in a column

I am trying to use a simple code to increment only the values in the “chat_id” column of a table.
For the table lz_chat_archive_dup1, the column “chat_id” is has empty strings (no values). This is the partial excerpt of the table :
mysql> select chat_id, fullname from lz_chat_archive_dup1 LIMIT 5;
+---------+--------------+
| chat_id | fullname |
+---------+--------------+
| | Yw |
| | Shah |
| | Sunny Duhel |
| | Leong Zi Yin |
| | Mohd Nasir |
+---------+--------------+
5 rows in set (0.00 sec)
I tried to insert a value for the name “Yw” like this and it worked :
mysql> UPDATE lz_chat_archive_dup1 SET chat_id = '383933' where fullname = 'Yw';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
So now the table is like this :
mysql> select chat_id, fullname from lz_chat_archive_dup1 LIMIT 5;
+---------+--------------+
| chat_id | fullname |
+---------+--------------+
| 383933 | Yw |
| | Shah |
| | Sunny Duhel |
| | Leong Zi Yin |
| | Mohd Nasir |
+---------+--------------+
5 rows in set (0.00 sec)
However, the number of rows in this table is 2589, and for me to do it one by one is tedious and time consuming :
mysql> select count(*) from lz_chat_archive_dup1;
+----------+
| count(*) |
+----------+
| 2589 |
+----------+
1 row in set (0.00 sec)
I thought I could use a code something like this to update/increment only that one column, but I don’t think this is the correct syntax for MySQL. Can you please help to correct the code to customize it to work in my situation :
DECLARE #counter int
SET #counter = 383933
UPDATE #lz_chat_archive_dup1
SET #counter = counter = #counter + 1
So with this code, what I am trying to achieve is increment the chat_id column so that the next value is always 1 integer higher than the previous one. So the first row is 383933, the next one should be 383934, 383935, 383936,…etc etc.
The table has > 2000 rows, so this is an excerpt of it :
mysql> select time, endtime, chat_id from lz_chat_archive_dup1 LIMIT 20;
+------------+------------+---------+
| time | endtime | chat_id |
+------------+------------+---------+
| 1594948770 | 1594948928 | 383933 |
| 1594950285 | 1594950542 | |
| 1594950708 | 1594951085 | |
| 1594953554 | 1594955581 | |
| 1594955956 | 1594956551 | |
| 1595215646 | 1595218410 | |
| 1595215648 | 1595216044 | |
| 1595216110 | 1595216138 | |
| 1595220816 | 1595221144 | |
| 1595221046 | 1595221584 | |
| 1595221448 | 1595221505 | |
| 1595222302 | 1595222653 | |
| 1595236468 | 1595236848 | |
| 1595236954 | 1595237033 | |
| 1595293418 | 1595293589 | |
| 1595303280 | 1595304388 | |
| 1595303410 | 1595303822 | |
| 1595303675 | 1595303986 | |
| 1595304153 | 1595306613 | |
| 1595304878 | 1595304995 | |
+------------+------------+---------+
20 rows in set (0.00 sec)
mysql>
Here is an approach using a user variable:
set #rn = 383933;
update #lz_chat_archive_dup1
set chat_id = (select #rn := #rn + 1)
order by name;
This will assign an incrementingn number to each row, following the alphabetical order of name. If there are ties, it is undefined which name will get which number (a reason why you should have a primary key column in your table).
Assuming the names are unique, you could use a join:
update lz_chat_archive_dup1 cad join
(select cad2.*, row_number() over () as seqnum
from lz_chat_archive_dup1 cad2
) cad2
on cad2.name = cad.name
set count = seqnum + 383933;
I think this might be the recommended approach in MySQL 8+. (The statement on the deprecation of variables is a little vague on whether it would apply to UPDATE.)
You can also use variables. The problem with your statement is:
SET #counter = counter = #counter + 1
This is not even setting the column in the table! It is setting a variable. Use := to set parameters. And I strongly recommend parentheses. So, you can do:
DECLARE #counter int;
SET #counter = 383933;
UPDATE #lz_chat_archive_dup1
SET counter = (#counter := #counter + 1);
Or, in a single statement:
UPDATE #lz_chat_archive_dup1 cad CROSS JOIN
(SELECT #counter := 383933) params
SET cad.counter = (#counter := #counter + 1);
If you can live with numbers starting from 1, following the alphabetic order of your fullname column, you can try with a helper table to run the update:
CREATE TABLE updtab
AS
SELECT
ROW_NUMBER() OVER(ORDER BY fullname) AS chat_id
, fullname
FROM lz_chat_archive_dup1;
Then , run the update:
UPDATE lz_chat_archive_dup1
SET chat_id = (
SELECT chat_id
FROM updtab
WHERE updtab.fullname=lz_chat_archive_dup1.fullname
)
;

mysql query returns empty set when data is there

+----+---------+--------------------+----------+------+---------------------+---------+-------------+------------+----------+
| id | pname | pmail | pgender | page | pdetails | pnumber | ddepartment | date | time |
+----+---------+--------------------+----------+------+---------------------+---------+-------------+------------+----------+
| 1 | karuna | karuna#gmail.com | female | 21 | hfsdh gfhdf shdh | 2332 | Surgeon | 2018-05-15 | 16:00:00 |
+----+---------+--------------------+----------+------+---------------------+---------+-------------+------------+----------+
This is my database table appointment.
Whenever I execute first two queries, they run perfectly
select * from appointment;(execute )
select * from appointment where pname = 'karuna';(execute)
but when I try to execute these two queries, the result I get is empty set
select *from appointment where pmail='karuna#gmail.com';(empty set (0.00 sec))
select *from appointment where ddepartment='Surgeon';(empty set (0.00 sec))

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.

MySQL Select Additional Rows on Same Table

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).

MySql selecting context limited by number starting from another one, no duplicate

Hey I need to make a MySql query and get from it some number of user activities, lets say 10, then after scrolling on page I need to take another portion of activities stored in DB and start from 10 to 20 and so on... As I made this already by loading the whole DB Content for user and then dynamically show it with AJAX and jQuery I need to change the method I am doing this. So my query looks like this:
SELECT some rows FROM table WHERE User_ID = #memberID ORDER By date LIMIT limit
As this query works to take only limited records from DB I have no idea how to make a parameter that would determine which records should we take now. The problem starts when user refreshes the page - we want to start from 0 and again go 10 by 10 down.
EDIT: I am giving the query 2 params (LIMIT and OFFSET) and then in jQuery function gonna try to increase both of them.
you can do it like this
example
mysql> SELECT * FROM MAXWELL;
+------+-------+
| ID | NAME |
+------+-------+
| 3 | TWO |
| 4 | FOUR |
| 5 | FIVE |
| 6 | SIX |
| 7 | SEVEN |
+------+-------+
5 rows in set (0.00 sec)
mysql> SELECT * FROM MAXWELL limit 0,2;
+------+------+
| ID | NAME |
+------+------+
| 3 | TWO |
| 4 | FOUR |
+------+------+
2 rows in set (0.00 sec)
mysql> SELECT * FROM MAXWELL limit 2,4;
+------+-------+
| ID | NAME |
+------+-------+
| 5 | FIVE |
| 6 | SIX |
| 7 | SEVEN |
| 10 | ten |
+------+-------+
4 rows in set (0.00 sec)