How can I query empty tables to check emptiness? - mysql

I have the following database structure.
applets
--id (incr)
applet_stats
--id (incr)
--applet_id (relates to applet.id)
--date ("Y-m-d" format)
Example data:
applets
1
2
3
applet_stats
1 1 2015.01.15
2 1 2015.01.15
3 1 2015.01.15
4 1 2015.01.15
5 2 2015.01.14
In the above example, we have 3 applets. Applet 1 has 4x statistics on 2015.01.15, Applet 2 1x statistics on 2015.01.14 (yesterday)
How can I query the database so I get the following output:
// Show me the applets which doesn't have any statistics on "2015.01.15".
[2,3]
I tried it myself using leftJoin but I'm overlooking something very simple so I get wrong result each time.
Ps. Would be even better in an Eloquent statement.

Eloquent way, assumings stats is hasMany relation:
$date = '2015-01-15';
Applet::whereDoesntHave('stats', function ($q) use ($date) {
$q->where('date', $date);
})->get();

SELECT id
from applets
where id not in(select distinct applet_id from applet_stats where date ='2015.01.15')
this may helps you

Related

Recursively running a MySQL function

I have a function in MySQL that needs to be run about 50 times (not a set value) in a query. the inputs are currently stored in an array such as
[1,2,3,4,5,6,7,8,9,10]
when executing the MySQL query individually it's working fine, please see below
column_name denotes the column it's getting the data for, in this case, it's a DOUBLE in the database
The second value in the MOD() function is the input I'm supplying MySQL from the aforementioned array
SELECT id, MOD(column_name, 4) AS mod_output
FROM table
HAVING mod_output > 10
To achieve the output I require* the following code works
SELECT id, MOD(column_name, 4) AS mod_output1, MOD(column_name, 5) AS mod_output2, MOD(column_name, 6) AS mod_output3
FROM table
HAVING mod_output1 > 10 AND mod_output2 > 10 AND mod_output3 > 10
However this obviously is extremely dirty, and when having not 3 inputs, but over 50, this will become highly inefficient.
Appart from calling over 50 individual querys, is there a better way to acchieve the same sort (see below) of output?
In escennce i need to supply MySQL with a list of values and have it run MOD() over all of them on a specified column.
The only data I need returned is the id's of the rows that match the MOD() functions output with the specified input (see value 2 of the MOD() function) where the output is less than 10
Please note, MOD() has been used as an example function, however, the final function required *should* be a drop in replacement
example table layout
id | column_name
1 | 0.234977
2 | 0.957739
3 | 2.499387
4 | 48.395777
5 | 9.943782
6 | -39.234894
7 | 23.49859
.....
(The title may be worded wrong, I'm not quite sure how else you'd explain what I'm trying to do here)
Use a join and derived table or temporary table:
SELECT n.n, t.id, MOD(t.column_name, n.n) AS mod_output
FROM table t CROSS JOIN
(SELECT 4 as n UNION ALL SELECT 5 UNION ALL SELECT 6 . . .
) n
WHERE MOD(t.column_name, n.n) > 10;
If you want the results as columns, you can use conditional aggregation afterwards.

MySql NOT IN failing to return empty set

I am currently having a problem when trying to select where a job is listed in the tbl_jobs table and has not been assigned to a delivery item in the tbl_delivery_items table by using a NOT IN subquery.
The sub query should return supplier_job_job_id 1 (which it does when you run this as a seperate query), with the NOT IN excluding the job with an id of 1. Alas, it is not working and causing me a headache by returningthe job with a job_id of 1 when I was expecting an empty set. Here is the codeigniter code generating the query:
$this->db->join("tbl_jobs", "tbl_jobs.job_id = tbl_supplier_jobs.supplier_job_job_id");
$this->db->where_not_in("supplier_job_job_id", "SELECT delivery_item_job_id FROM tbl_delivery_items");
$result = $query->result_array();
echo $this->db->last_query();
return $result;
Here is the query it generates:
SELECT * FROM (`tbl_supplier_jobs`) JOIN `tbl_jobs` ON `tbl_jobs`.`job_id` = `tbl_supplier_jobs`.`supplier_job_job_id` WHERE `supplier_job_job_id` NOT IN ('SELECT delivery_item_job_id FROM tbl_delivery_items') AND `supplier_job_supplier_id` = '1' ORDER BY `tbl_jobs`.`job_number` DESC
And here is the data:
tbl_supplier_jobs
supplier_job_id | supplier_job_job_id | supplier_job_supplier_id
1 1 1
2 2 2
tbl_jobs
job_id | job_number | job_description | job_delivered
1 1024 aaaaa 0
2 2048 bbbbb 0
tbl_delivery_items
delivery_item_id | delivery_item_delivery_id | delivery_item_job_id | delivery_item_toa | delivery_item_pallet_quantity | delivery_item_box_quantity
1 1 1 2014-08-18 16:23:04 2 1
Any ideas?
The problem is that the subquery is rendered as a string. You can see this clearly in the generated query that you supplied.
This seems to be a limitation in the where_not_in method of CodeIgniter. A possible solution, change the code to call the where method and render a slightly larger part of the query yourself:
$this->db->where("supplier_job_job_id NOT IN (SELECT delivery_item_job_id FROM tbl_delivery_items)");
The query isn't executing the subquery it is using the string value:
`supplier_job_job_id` NOT IN (
'SELECT delivery_item_job_id FROM tbl_delivery_items'
)
Will check if supplier_job_job_id equals the string 'SELECT delivery_item_job_id FROM tbl_delivery_items'.
You should consider a LEFT JOIN to tbl_delivery_items and a WHERE condition of delivery_item_job_id IS NULL.. which should be fairly easy in your framework.
Your subselect is being output as a string. Note that it is in single quotes in your resulting query. That of course will not work.
I would actually question your intended approach here. As your tbl_delivery_items table gets bigger and bigger your query will get slower and slower. This is not a scalable approach. You should revisit your table schema and get a more direct way of flagging completed deliveries.

MySQL dynamic cross tab

I have a table like this:
way stop time
1 1 00:55
1 2 01:01
1 3 01:07
2 2 01:41
2 3 01:47
2 5 01:49
3 1 04:00
3 2 04:06
3 3 04:12
and I want a table like this:
stop way_1 way_2 way_3 (way_n)
1 00:55 04:00
2 01:01 01:41 04:06
3 01:07 01:47 04:12
5 01:49
There are many solutions online about MySQL cross tab (pivot table), but how can I do this if I don't know how many "way" are there?
Thanks
The number and names of columns must be fixed at the time you prepare the query. That's just the way SQL works.
So you have two choices of how to solve this. Both choices involve writing application code:
(1) Query the distinct values of way and then write code to use these to construct the pivot query, appending as many columns in the SELECT-list as the number of distinct values.
foreach ($pdo->query("SELECT DISTINCT `way` FROM `MyTable`") as $row) {
$way = (int) $row["way"];
$way_array[] = "MAX(IF(`way`=$way, `time`)) AS way_$way";
}
$pivotsql = "SELECT stop, " . join(", ", $way_array) .
"FROM `MyTable` GROUP BY `stop`";
Now you can run the new query, and it has as many columns as the number of distinct way values.
$pivotstmt = $pdo->query($pivotsql);
(2) Query the data row by row as it is structured in your database, and then write code to pivot into columns before you display the data.
$stoparray = array();
foreach ($pdo->query("SELECT * FROM `MyTable`") as $row) {
$stopkey = $row["stop"];
if (!array_key_exists($stopkey, $stoparray)) {
$stoparray[$stopkey] = array("stop"=>$stopkey);
}
$waykey = "way_" . $row["way"];
$stoparray[$stopkey][$waykey] = $row["time"];
}
Now you have an array of arrays that looks the same as if you had run a pivot query, but the actual SQL you ran was a lot simpler. You post-processed the query result into a different set of arrays.

MYSQL - SELECT ALL FROM TABLE if

I have a (nice) mysql table built like this :
Fields Datas
id (pk) 1 2 3 4 5 6
master_id 1000 1000 1000 2000 2000 2000 ...
master_name home home home shop shop shop ...
type_data value common client value common client ...
param_a foo_a 1 0 bar_a 0 1 ...
param_b foo_b 1 0 bar_b 1 0 ...
param_c foo_c 0 1 bar_c 0 1 ...
... ... ... ... ... ... ... ...
All these datas are embed in a single table. Each datas are dispatched on 3 "columns" set (1 for the values, 1 for identifying if these are common values and one for identifying client values). It's not the best I got but many other scripts depends on this structure.
I'd need sthg like this:
SELECT parameters name (eg param_a, param_b..) and their values (eg foo_a, foo_b..)
WHEN master_id=? AND type_data=(common or client) (eg for values=1 on the 2nd column)
.
in order to get the parameters hash for a particular master_id like
param_a => foo_a
param_b => foo_b
param_c => foo_c
...
I could not succeed in self joining on the same table till now but I guess it should be feasible. (I'd like to avoid to do several queries)
Thx in advance
I think you are talking about pivoting the data? If so, see here: http://en.wikibooks.org/wiki/MySQL/Pivot_table and here: http://dev.mysql.com/tech-resources/articles/wizard/print_version.html

MySQL Inner Query with a Where and Group by conditions in cakephp

i am having a table named Reports with
id report_id user_id
1 1 5
2 1 5
3 1 5
4 2 5
5 2 5
6 3 6
7 3 6
8 4 1
9 4 1
10 4 1
i am trying to write a Query such that user_id = 5 and to find how many reports he has created.(Answer should be of 2 )
i have a Wrote a Mysql Query as
select count(distinct report_id) from Reports where user_id=5
i m trying the same MYSQl sub Query inside the Foreach users loop where my 5 is from $user['User']['id'];
how to write the MYSQL Query above inside this for loop in cakephp Framework....
foreach($users as & $user):
echo "User id ".$user['User']['id'];
$user['User']['report_count'] = $this->Report->find('count',
array('conditions'=>array('Report.user_id'=>$user['User']['id'])));
endforeach;
$this->set('users', $users);
Please suggest me.......HOw to write the above Mysql Query in cakephp
You want to use the following functions GROUP BY and COUNT
Your query could look somewhat like this
select count(distinct report_id) from Reports where user_id=5
If this is a list of users you are showing in your application... you could significantly reduce the number of queries you are running.
eg. for 100 users you will be running 100 queries instead you can run a single single query to extract the user_id and count of reports by each user
select count(distinct report_id) as count,user_id from Reports where user_id IN (1,2) GROUP BY user_id;
OR if you want to run seperate queries for each user
select count(distinct report_id) as count,user_id from Report where user_id=5;
Try this:
$user['User']['report_count'] = $this->Report->find('count',
array( 'conditions' => array('Report.user_id' => $user['User']['id']),
'fields' => 'DISTINCT Report.report_id'
)
);
It should fetch all distinct report_ids for a given user_id, then count them. Basically, it should run the query:
SELECT DISTINCT report_id FROM Reports WHERE user_id=$user['User']['id']
(after substituting the value of $user['User']['id']), then count the number of rows in the result. Caveat: I don't use CakePHP in real life, I just read the documentation; your mileage may vary. As halocursed mentions, running a single SQL query on your own would be more efficient than calling find(...) for each user ID. You could also try:
$report_counts = $this->Report->find('list',
array( 'conditions' => array('Report.user_id' => array_map(create_function('$user', 'return $user["User"]["id"];'), $users)),
'group' => array('Report.user_id'),
'fields' => array('Report.user_id', 'COUNT(DISTINCT Report.report_id) AS report_count')
)
);
foreach ($users as &$user) {
$user['User']['report_count'] = $report_counts[$user['User']['id']];
}
However, I don't know if CakePHP will accept aggregate functions in the 'fields' parameter, and I don't know as though find('list', ...) will pick Report.user_id as the array index. If you're having problems with the latter, you could switch to a [find('all', ...)][3] call and loop over $report_counts rather than $users. I didn't take this approach because I don't know the structure of $users, such as how it's indexed.