The query below works fine in when I try it in the console.
mysql> SELECT COUNT(l.ID), a.MAX_PER_PRD, a.PLURAL, d.TIME_DENOM FROM logro l, challenge c, lib_accomp_type a, lib_deporte d WHERE l.PERIOD=3 AND l.GAME_ID=2 AND l.PLR_ID=3 AND l.ACC_TYPE_ID=11 AND a.sport=d.ID AND c.ACC_TYPE_ID=a.ID AND l.ACC_TYPE_ID=c.ACC_TYPE_ID;
+-------------+-------------+--------------------+------------+
| COUNT(l.ID) | MAX_PER_PRD | PLURAL | TIME_DENOM |
+-------------+-------------+--------------------+------------+
| 0 | 3 | general commodities| quarter |
+-------------+-------------+--------------------+------------+
1 row in set (0.01 sec)
However, when I wrap it in a perl->DBI statement handle and fetch it with $sth->fetchrow_array the second value is undefined.
my $q = "SELECT COUNT(l.ID), a.MAX_PER_PRD, a.PLURAL, d.TIME_DENOM
FROM logro l, challenge c, lib_accomp_type a, lib_deporte d
WHERE l.PERIOD=?
AND l.GAME_ID=?
AND l.PLR_ID=?
AND l.ACC_TYPE_ID=?
AND a.sport=d.ID
AND c.ACC_TYPE_ID=a.ID
AND l.ACC_TYPE_ID=c.ACC_TYPE_ID";
my $sth = $dbh->prepare($q);
$sth->execute(3, 2, 3, 11);
my ($CNT, $MAX, $ANAMEP, $TD) = $sth->fetchrow_array;
print "COUNT: ", $CNT;
print "MAX: ", $MAX;
$ perl test_sql2.pl
Use of uninitialized value $MAX in print at test_sql2.pl line 29.
COUNT: 0MAX:
Any idea as to what I could be doing wrong?
Depending on your mysql client/library version, mysql handles this situation differently.
For mysql <= 5.6, see Group By Handling
For mysql = 5.7, see Group By Handling
You query has a count of 0, yet there are values returned for the other columns. That doesn't seem to make any sense. It seems that running through perl is actually doing the logical thing and mysql is just populating the MAX_PER_PRD, PLURAL, TIME_DENOM columns with arbitrary values.
The main issue here, is that you referencing non-aggregated columns without them being part of a group by clause.
Perhaps if you include a sample data set, it could help us get to the result your are looking for.
Related
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.
Problem: My Query returns NULL
Potential issues: Subquery formatted wrong and only works if some data I want to sort out is in the dataset.
Example of today's code:
SELECT production_order
,SUM(total_working_time_h) - (SELECT SUM(total_working_time_h) FROM {$table} WHERE production_order = '$production_order' AND (station = '出货检验 | OQC' OR production_type = 'Rework')) AS total_working_time_h_edit
,SUM(no_of_defects) AS no_of_defects_during_production
FROM {$table}
WHERE production_order = '$production_order'
This works great as long as I have either "Rework" and/or "'出货检验 | OQC'" logged in my database for this production order. If not, I won't get any data at all but NULL. So my problem is somewhere in my subquery I think:
SELECT SUM(total_working_time_h) FROM {$table} WHERE production_order = '$production_order' AND (station = '出货检验 | OQC' OR production_type = 'Rework')
I've tried adding a "0" to make sure it's get 0 and not NULL without success like follows:
(0 + SELECT SUM(total_working_time_h) FROM {$table} WHERE production_order = '$production_order' AND (station = '出货检验 | OQC' OR production_type = 'Rework')
Example dataset formated as text:
production_order part_nr station total_working_time_h
26135 129-108816B-UL 压接 | Crimping 1.42
26135 129-108816B 线束组装 | Harness Assembling 7.67
26135 129-108816 测试 | Testing 0.83
26135 129-108816B 外观全检 | Appearance inspection 0.83
Gives this output:
production_order,total_working_time_h_edit
26135, NULL
I want this output:
production_order,total_working_time_h_edit
26135, 10,45
If my dataset hold the station I want to sort out or the production_type I want to sort out everything works as it should. But if both of those is missing in the dataset it returns NULL, since what I think is because the subquery returns 0.
An example of different datasets I'm using. If I have the data marked with green cells in the dataset it will work. If not, I get the return NULL as above.
So how to make my subquery to not return NULL?
Managed to solve the question myself.
Problem: Subquery returned NULL instead of 0.
Solution: Added COALESCE(,0) to my sub querys function SUM() like this:
COALESCE(SUM(total_working_time_h),0)
By doing so it returns 0 instead of NULL when the SUM() actually wants to return NULL. That solved my problem.
I have a database that lists a few area codes, area code + office codes and some whole numbers and a action. I want it to return a result by the digits given but I am not sure how to accomplish it. I have some MySQL knowledge but its not very deep.
Here is a example:
match | action
_____________________
234 | goto 1
333743 | goto 2
8005551212| goto 3
234843 | goto 4
I need to query the database with a full 10 digit number -
query 8005551212 gives "goto 3"
query 2345551212 gives "goto 1"
query 3337431212 gives "goto 2"
query 2348431212 gives "goto 4"
This would be similar to the LIKE selection, but I need to match against the database value instead of the query value. Matching the full number is easy,
SELECT * FROM database WHERE `match` = 8005551212;
First the number to query will always be 10 digits, so I am not sure how to format the SELECT statement to differentiate the match of 234XXXXXXX and 234843XXXX, as I can only have one match return. Basically if it does not match the 10 digits, then it checks 6 digits, then it will check the 3 digits.
I hope this makes sense, I do not have any other way to format the number and it has to be accomplished with just a single SQL query and return over a ODCB connection in Asterisk.
Try this
SELECT match, action FROM mytable WHERE '8005551212' like concat(match,'%')
The issue is that you will get two rows in one case .. given your data..
SELECT action
FROM mytable
WHERE '8005551212' like concat(match,'%')
order by length(match) desc limit 1
That should get the row that had the most digits matched..
try this:
SELECT * FROM (
SELECT 3 AS score,r.* FROM mytable r WHERE match LIKE CONCAT(SUBSTRING('1234567890',1,3),'%')
UNION ALL
SELECT 6 AS score,r.* FROM mytable r WHERE match LIKE CONCAT(SUBSTRING('1234567890',1,6),'%')
UNION ALL
SELECT 10 AS score,r.* FROM mytable r WHERE match LIKE CONCAT(SUBSTRING('1234567890',1,10),'%')
) AS tmp
ORDER BY score DESC
LIMIT 1;
What ended up working -
SELECT `function`,`destination`
FROM reroute
WHERE `group` = '${ARG2}'
AND `name` = 0
AND '${ARG1}' LIKE concat(`match`,'%')
ORDER BY length(`match`) DESC LIMIT 1
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.
I need a query that find the recommended TV shows for an user, based on the TV Shows he is following.
Do to this I have the following tables:
the table Progress that contains wich show the user is following and the percentage of seen episodes (to solve this problem we can assume I have only one user in the database)
the table Suggested that contains _id1,_id2 and value (value is the strength of the connections between the show with id=_id1 and the show with id=_id2: the more value is great, the more the shows have something in common).
Note that in this table applies the commutative property, so the strength of the connection between id1 and _id2 is the same of _id1 and _id2. Moreover there aren't two rows such as ROW1._id1=ROW2._id2 AND ROW1._id2 = ROW2._id1
the table ShowCache that contains the details about a TV Show, such as name etc..
The following query is what I'm trying to do, but the result is an empty set:
SET #a = 0; //In other tests this line seem to be necessary
SELECT `ShowCache`.*,
(SUM(value) * (Progress.progress)) as priority
FROM `Suggested`,`ShowCache`, Progress
WHERE
((_id2 = Progress.id AND _id1 NOT IN (SELECT id FROM Progress) AND #a:=_id1)//There is a best way to set a variable here?
OR
(_id1 = Progress.id AND _id2 NOT IN (SELECT id FROM Progress) AND #a:=_id2))
AND `ShowCache`._id = #a //I think that the query fails here
GROUP BY `ShowCache`._id
ORDER BY priority DESC
LIMIT 0,20
I know the problem is related to the usage of variables, but I can't solve it. Any help is really appreciated.
PS: the main problem is that (because of the commutative propriety), without variables I need two queries, wich takes about 3 secs to begin executed (the query is more complex than the above). I'm really trying to make a single query to do this task
PPS: I tied also with an XOR operation, that results in an infinite loop?!?!? Here's the WHERE clause I tried:
((_id2=Progress.id AND #a:=_id1) XOR (_id1=Progress.id AND #a:=_id2)) AND `ShowCache`._id = #a
EDIT:
I come up with this WHERE conditions without using any variable:
(_id2 = Progress.id OR _id1 = Progress.id)
AND `ShowCache`._id = IF(_id2 = Progress.id, _id1,_id2)
AND `ShowCache`._id NOT IN (SELECT id FROM Progress)
It works, but it is very slow.
Your attempt to use xor is clever. If you want to get the nonmatching value you want to use bitwise XOR which is ^
Progress.id ^_id1 ^ _id2
3 ^ 2 ^ 3 = 2
2 ^ 2 ^ 3 = 3
You can use this trick to setup a join and really simplify your query (eliminate the OR's and NOT IN's and do it in one query without variables.)
select users.name as username, showcache.name as show_name,
sum(progress * value) as priority from users
inner join progress on users.id = progress.user_id
inner join suggested on progress.show_id in (suggested.id_1, suggested.id_2)
inner join showcache on showcache.id =
(suggested.id_1 ^ suggested.id_2 ^ progress.show_id)
where showcache.id not in
(select show_id from progress where user_id = users.id)
group by showcache.id
order by priority desc;
I also setup a fiddle to demonstrate it:
http://sqlfiddle.com/#!2/2dcd8/24
To break it down. I created a users table with a single user (but the solution will work with multiple users.)
The select and join to progress is straightforward. The join to suggested uses IN as an alternative to writing it with OR
The join to showcache is where the bitwise XOR happens. One of the id's links up to the progress.show_id and we want to use the other one.
It does include a not in to exclude shows already watched from the results. I could have changed it to not exists? but it seems clearer this way.
You're setting #a's value twice within the where clause, meaning that the query is actually boiling down to:
...
WHERE ... AND `ShowCache`._id = _id2
MySQL evalutes variable assignments in a first-encountered order, so you should leave #a constant until the END of the clause, then assign a new value, e.g
mysql> set #a=5;
mysql> select #a, #a+1, #a*5, #a := #a + 1, #a;
+------+------+------+--------------+------+
| #a | #a+1 | #a*5 | #a := #a + 1 | #a |
+------+------+------+--------------+------+
| 0 | 1 | 0 | 1 | 1 |
| 1 | 2 | 5 | 2 | 2 |
| 2 | 3 | 10 | 3 | 3 |
+------+------+------+--------------+------+
Note that #a's value in the first 3 columns remains constant, UNTIL mysql reaches the #a := #a +1, after which #a has a new value
So perhaps your query should be
set #a = 0;
select #temp := #a, ..., #a := _id2
where
((_id2 = Progress.id AND _id1 NOT IN (SELECT id FROM Progress) AND #temp =_id1)
...
etc...