Select count with WHERE and OR but specifying a uniqueness - php

Hi everyone I am in a problem.
I have a table that contains the job requests, which is called: richieste
Another table that contains the appointments which is called: appuntamenti
I have to count how many times the id of a worker, in this case the 57 is present when there is a join between the table: richieste and appuntamenti.
nothing easier.
$q_count_appto_manager = $connessione->prepare("
SELECT count('ID_Richiesta')
FROM richieste
LEFT JOIN appuntamento
ON richieste.ID_Richiesta = appuntamento.appto_id_richiesta
WHERE operato_manager = ?
OR operato_manager_capo_a_manager = ?
OR team_manager = ?
OR team_manager_capo_a_team_manager = ?
AND appuntamento.appto_stato = 'NC'
");
$q_count_appto_manager->bind_param("iiii", $pro,$pro,$pro,$pro);
$q_count_appto_manager->execute();
$r_count_appto_manager = $q_count_appto_manager->get_result();
$rcam=mysqli_fetch_array($r_count_appto_manager);
?>
<?php
if ($rcam[0] == 0) {
echo $rcam[0];
} else {
echo $rcam[0];
}
now the problem begins, the worker with id: 57, can have more positions within the table: richieste, as you can read from the query, in the OR part.
and as you can see from the image
57 ID
so in this case the query will count every time the 57 is present in those positions, generating as output results: 4.
The problem is that I'm asking him to count 57 when he is in those positions, only when there is a join between the two tables, which as a true result should come out: 1
So it doesn't take the where condition into account as unique, but just counts how many times 57 exists in those positions.
How can I specify an attribute of uniqueness, limiting the query to count only when the 57 is in those positions and there is a join between the two tables?

AND has higher precedence than OR, so you need to use parentheses:
WHERE (operato_manager = ? OR operato_manager_capo_a_manager = ? OR
team_manager = ? OR team_manager_capo_a_team_manager = ?)
AND appuntamento.appto_stato = 'NC'

You might find it simpler to use IN with a single parameter:
WHERE appuntamento.appto_stato = 'NC' AND
? IN (operato_manager, operato_manager_capo_a_manager, team_manager, team_manager_capo_a_team_manager)

Related

Slow query with where on joined column

I tried to combine 2 queries into 1 by using JOINs
// Query 1
$entity = \DB::select("
SELECT memo_id
FROM entities
WHERE entity_type = 4
AND entity_id = '".$entity_nr."'
LIMIT 1
");
$memo = \DB::select("
SELECT memo
FROM memos
WHERE id = '".$entity[0]->memo_id."'
LIMIT 1
");
// Query 2
$memo = \DB::select('
SELECT memo
FROM memos
JOIN entities ON "memos"."id" = "entities"."memo_id"
WHERE "entities"."entity_type" = 4
AND "entities"."entity_id" IN (?)
LIMIT 1
', [$entity_nr]);
The 2 query's of Query 1 are done in less than a second. Query 2 takes several seconds. If i remove the where clause of Query 2 it executes fast. Using AND "entities"."entity_id" = ? did'nt helped as well.
Howto solve this?
UPDATE 2020-09-27
Refactoring my question. Hopes this makes it clearer. Expected output is to get the memo. There is always only 1 possible match. In the example code im not checking for existence of the result, because it doesn't really add something to the question.
Database which im using is "Actian Zen database".
Table structure
//////////////////////////
// Table: "entity_memo" //
//////////////////////////
CREATE TABLE "entity_memo" (
"entity_type" SMALLINT,
"entity_id" CHAR(15),
"memo_id" INTEGER
);
CREATE UNIQUE INDEX "key0" ON "entity_memo" ( "entity_type", "entity_id", "memo_id" );
CREATE INDEX "key1" ON "entity_memo" ( "memo_id", "entity_type", "entity_id" );
//////////////////////////
// Table: "memos" //
//////////////////////////
CREATE TABLE "memos" (
"id" INTEGER,
"memo" LVAR(32002)
);
CREATE UNIQUE INDEX "key0" ON "memos" ( "id" );
Option 1 (= fast, but 2 queries)
$entity_type = 1;
$entity_id = 'ABC123456';
$entity = \DB::select('
SELECT memo_id
FROM entity_memo
WHERE entity_type = ?
AND entity_id = ?
LIMIT 1
', [$entity_type, $entity_id]
);
$memo = \DB::select('
SELECT memo
FROM memos
WHERE id = ?
LIMIT 1
', [$entity[0]->memo_id]
);
return $memo[0]->memo;
Option 2 (= slow, but 1 query only)
$entity_type = 1;
$entity_id = 'ABC123456';
$memo = \DB::select('
SELECT memo
FROM memos
JOIN entity_memo ON "memos"."id" = "entity_memo"."memo_id"
WHERE "entity_memo"."entity_type" = ?
AND "entity_memo"."entity_id" = ?
LIMIT 1
', [$entity_type, $entity_id]
);
return $memo[0]->memo;
It will be look simpler, if you write it without JOINs.
SELECT ent.unique_id, mem.memo
FROM entities ent, memos mem
WHERE ent.unique_id = mem.unique_id
AND ent.entity_type = 4
AND ent.entity_id = '".$entity_nr."'
But the cause of query working slow is in tables itself. You should to add indexes to PK and FK columns for query to work faster.

Get count of multiple fields in MySQL

I am unable to get 3 count fields from 3 different tables by using this SQL query below. Can someone help me out where I mistaken. The first count is assigning to another 2 fields. Means if I get 'total_scenarios' count as 10 the remaining 2 options(total_career_sketches, video_count) are taking same value 10.
$this->db->select('users.id,users.name,users.user_lname,users.email,
count(fc_scenarios.user_id) as total_scenarios, count(career_sketch.user_id)
as total_career_sketches, count(video_tracker.user_id) as video_count
,career_timeline.filled_modules');
$this->db->from('users');
$this->db->join('fc_scenarios','users.id = fc_scenarios.user_id AND
fc_scenarios.status = "A" AND fc_scenarios.type = "o"','left');
$this->db->join('career_sketch','users.id = career_sketch.user_id AND
career_sketch.status = "A" AND career_sketch.type = "o"','left');
$this->db->join('video_tracker','users.id = video_tracker.user_id','left');
$this->db->join('career_timeline','users.id =
career_timeline.user_id','left');
$this->db->where('users.inkwiry_user != ',1);
$this->db->where('users.status','A');
$this->db->group_by('users.id');
Thanks,
Sateesh
You may need to count distinct values for your joined tables, I guess due to one to many relation you are getting multiple rows repeated rows because of joins, I suggest you to use distinct inside your count function like
$this->db->select('users.id,users.name,users.user_lname,users.email,
count(distinct fc_scenarios.id) as total_scenarios,
count(distinct career_sketch.id) as total_career_sketches,
count(distinct video_tracker.id) as video_count,
career_timeline.filled_modules')
Also your query is invalid because group by clause has only one column o group rows but in select list your are trying to select other columns too which are not included in group by and neither aggregate
You can try with following query, it will work
$this->db->select('users.id,users.name,users.user_lname,users.email,
count(distinct fc_scenarios.id) as total_scenarios, count(distinct career_sketch.id)
as total_career_sketches, count(distinct video_tracker.id) as video_count
,career_timeline.filled_modules');
$this->db->from('users');
$this->db->join('fc_scenarios','users.id = fc_scenarios.user_id AND
fc_scenarios.status = "A" AND fc_scenarios.type = "o"','left');
$this->db->join('career_sketch','users.id = career_sketch.user_id AND
career_sketch.status = "A" AND career_sketch.type = "o"','left');
$this->db->join('video_tracker','users.id = video_tracker.user_id','left');
$this->db->join('career_timeline','users.id =
career_timeline.user_id','left');
$this->db->where('users.inkwiry_user != ',1);
$this->db->where('users.status','A');
$this->db->group_by('users.id');

ORDER BY not working in MySQL

while ($categories = mysql_fetch_array($category_result)) {
$item_result = mysql_query("SELECT * FROM zw_".$categories['Category']."s WHERE ItemId = '".$categories['Id']."' ORDER BY Level");
$item = mysql_fetch_assoc($item_result);
echo $item['Level'];
The output of this is
15
35
55
75
95
115
135
150
15
27
48
68
83
11
40
62
80
95
110
125
I cant really find a pattern here. I want it to go from the lowest number to highest number, which ORDER BY is supposed to do, right? Level is always INT and this is inside a while loop.
Check this
while ($categories = mysql_fetch_array($category_result)) {
$item_result = mysql_query("SELECT * FROM zw_".$categories['Category']."s WHERE ItemId = '".$categories['Id']."' ORDER BY Level ASC");
$item = mysql_fetch_assoc($item_result);
echo $item['Level'];
Try iterate over the result of the inner query .. eg:
while ($categories = mysql_fetch_array($category_result)) {
$item_result = mysql_query("SELECT * FROM zw_".$categories['Category']."s WHERE ItemId = '".$categories['Id']."' ORDER BY Level");
wwhile($item = mysql_fetch_assoc($item_result)) {
echo 'Category : ' . $categories['Id'] . ' Level : ' . $item['Level'];
}
}
I think you are constructing the table name dynamically, using data you have read from some other table (or maybe elsewhere). Hence, you want records from a collection of separate tables, and then to sort the complete set.
Perhaps you could build your SQL to create a "UNION" for each unique table, so the query runs only once and does its sorting on the entire result set. Possibly, a union clause (OK, the first clause is not introduced with "UNION")!) for each ($categories['Category'], $categories['Id']) combination will be too much for your RDBMS to handle. So, you could stick to one clause per $categories['Category'] and build all the associated $categories['Id']s into an "IN" condition.
Worth considering whether it's better to stick with what you have, and write some code to sort the results you're getting.
The field in database is numeric ? Try to specify the type of sort,... order by Level asc for example.
Checkout http://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html

Establish the order of some values

I have a series of queries that find out what is the best position every user had over a series of events (note: all users have the same $points_pos, so I am looking at a discriminating value). The query is looped for every user.
$max=$amount+1;
$i=1;
$highestsofar="99";
$numpointsall = "SELECT driver, position FROM standings_drivers WHERE season='42' AND points='$points_pos'";
$numall = mysql_query($numpointsall);
while ($i<$max) {
while ($row = mysql_fetch_row($numall)) {
$driver_id = $row[0];
$posvar = "SELECT position FROM results WHERE compId='$compId' AND driverId='$driver_id' AND eventID>='$firstevent' AND eventID<='$lastevent' AND (eventSession!='T' AND eventSession!='P' AND eventSession!='Q' AND eventSession!='Q1' AND eventSession!='Q2' AND eventSession!='QA') ORDER BY position ASC LIMIT 1";
$posres = mysql_query($posvar);
while ($row = mysql_fetch_row($posres)) {
$highestpos = $row[0];
}
$i++;
}
}
Having established the $highestpos for each of the $driver_id, how can I arrange them in order of best position (that is, the ones with the lowest $highestpos)?
Ideally, I want to achieve something that tells me:
$driver_id = 1
$driver_id = 2 etc
so that I can amend a table by putting them in the correct order of position.
EDIT: additional info
The results table look like this:
ID compId eventId eventSession driverId position
1 2 739 R 563 7
2 2 739 R 903 1
3 2 562 R 874 16
...
In the case above, assuming that 739 and 562 are the IDs of events in the range, I would like to order the three users in driverId as follows:
903 = 1st
563 = 2nd
874 = 3rd
Thank you for your help!
One thing about SQL is that it's typically much better than you (or I) are at getting data. The developers and architects for Microsoft, Oracle, etc. have spent a great deal of time and effort working on the best ways to select data, so trying to duplicate their efforts (like looping over results and getting values, etc.) is usually a mistake.
All of your code can likely be replaced with a single SQL query:
SELECT
SD.driver,
MIN(R.position) AS highest_position
FROM
Standings_Drivers SD
INNER JOIN Results R ON
R.driver = SD.driver AND
R.compId = ? AND
eventID >= ? AND
eventID <= ? AND
eventSession NOT IN ('T', 'P', 'Q', 'Q1', 'Q2', 'QA')
WHERE
SD.season = '42' AND -- Should this really be a string and not an integer?
SD.points = ?
GROUP BY
SD.driver
ORDER BY
MIN(R.position)
The question marks are where you would pass in your various parameters. Make sure that you're are executing this as a parameterized query and not just building up a complete string. I don't program in PHP, so I don't know the syntax for that. Googling for "sql injection php" should help you out there though.

MySQL Count in PHP while loop only returns one result then Null

Ok, so I have some MySQL tables as follows:
Buildings
Building-ID Building-Name
===========----=============
1 Building-1
2 Building-2
3 Building-3
4 Building-4
Building-1
Mroom State
=====----======
1 Booked
2 Empty
3 Empty
4 Empty
Building-2
Mroom State
=====----======
1 Booked
2 Empty
3 Empty
4 Empty
And a query in PHP as follows (Ignore the hard coded while, I've simplified the code a bit):
$sql = "select * from Buildings";
$result = mysql_query ($sql) or die(mysql_error());
while ($row = mysql_fetch_array($result))
{
$building[] = $row['ward_name'];
}
$v1 = 0;
while ($v1 < 4)
{
$sql = "SELECT COUNT(*) FROM `$building[$v1]` WHERE state = 'Empty'";
$result = mysql_query($sql) or die(mysql_error());
$count = mysql_result($result, 00);
var_dump($count[$v1]);
$v1 = $v1 + 1;
}
To my way of thinking this should create an array of the buildings contained in the "Buildings" table, start a loop, load the building name from the array and provide a row count for the table of how many rows contain "Empty" in the state column. What it actually does is provide a count for the first table and then provides "NULL" for the rest.
I'd appreciate any help you can give me.
Cheers!
What about changing your data model?
Table buldings can be kept as is:
Buildings
Building-ID Building-Name
===========----=============
1 Building-1
2 Building-2
3 Building-3
4 Building-4
New table:
Rooms
Building-ID Mroom State
===========-=====-=====
1 1 1
1 2 0
2 1 0
State 0 = Empty, State 1 = Booked
Then use a join with group by:
select count(*) from buildings b inner join rooms r on r.bid = b.id where r.state = 0 group by b.id;
Then you will get a row for each building with the count of empty rooms. You won't need a table for each building.
This does noit make sense:
$count = mysql_result($result, 00);
var_dump($count[$v1]);
you mean to write:
$count[$v1] = mysql_result($result, 00);
var_dump($count[$v1]);
Also do not use several tables with names matching columns of other tables.
You can use one table with a primary key that spans two columns instead, for example create primary key on($buildingid,$roomid)
so that the table has columns $buildingid,$roomid, and $state.
mysql_result() returns a string, not an array.
Modify the code and check that now it works as expected.
var_dump($count);

Categories