disable unique sql row result constraint - php

I'm looping through a table, quests, storing the NPC ids per that Quest, then looping through table NPCs, and returning all NPC data per NPC id.
The values boxed in red should be returning.
Table: quests
Table: npcs
I'm looping through all received NPC_ids from quests table, and dump array to make sure it's not missing any data. No data missing.
var_dump($allNPCIDs); //all 5 results
Then dump the query to make sure imploded string isn't missing any data. No data missing.
var_dump($qry); //query shows all 5 results
Issue:
But when I dump the $row, I'm missing the duplicate npd_id:
var_dump($row); //missing 1 row, the duplicate npc_id
PHP:
foreach ($allNPCIDsPerQuest as $item) {
foreach ($item as $value) {
array_push($allNPCIDs, $value);
}
}
echo "DUMPING ARRAY";
var_dump($allNPCIDs);
//load NPC data
$qry =
'SELECT N.*
FROM npcs N
WHERE npc_id IN ("' . implode('", "', $allNPCIDs) . '")';
echo "DUMPING QRY STRING";
var_dump($qry);
$result = $mysqli->query($qry) or die(mysqli_error($mysqli));
$i = 0;
echo "DUMPING ROW DATA";
while ($row = $result->fetch_assoc()) {
var_dump($row);
$i++;
}
How do I turn off constraints for deleting duplicate row data in phpMyAdmin mySQL DB?

It's a not a constraint you can turn off. It's the structure of the query you are executing. Using an IN (1,2,3,4,1) is the same as using an IN (1,2,3,4). It is just a condition to filter the npcs table and decide if a particular row is to be selected or not. Having the id listed twice does not make the row exist twice in the npcs table... so it cannot be selected twice.
What you want cannot be done with that SELECT.
You either use a UNION:
(SELECT * FROM npcs WHERE npc_id=1) UNION
(SELECT * FROM npcs WHERE npc_id=2) UNION
(SELECT * FROM npcs WHERE npc_id=3) UNION
(SELECT * FROM npcs WHERE npc_id=4) UNION
(SELECT * FROM npcs WHERE npc_id=1)
or you first insert the ids in a temp table and then SELECT like this:
SELECT N.* FROM npcs N JOIN temptable T on N.npc_id=T.npc_id
or you do it client side, with a loop, executing a query for each ID and putting the data together.
There may be other solutions, but they don't come to mind right now.

This is no constraint in phpMyAdmin, but how SQL works.
SELECT N.* FROM npcs N would return 5 rows (npc_id 1 to 5). WHERE limits this to rows that match your conditions. You don't get extra rows if you repeat conditions.
You could extract the column npc_id from table quests into a lookup table quests_to_npcs with the columns quest_id and npc_id. This would contain a row for each npc in a quest.
Your query might look like this:
SELECT n.*
FROM quests AS q
INNER JOIN quests_to_npcs AS q2n ON q.quest_id = q2n.quest_id
INNER JOIN npcs AS n ON q2n.npc_id = n.npc_id

You should create another table called something like quest_npcs.
CREATE TABLE quest_npcs (
quest_id INT,
npc_id INT
);
Then you can simply store all the associated npc_ids for each quest on a row each.
To then pull the information for all the NPCs for a particular quest it's a straightforward join.
SELECT npcs.*
FROM quest_npcs
INNER JOIN npcs
ON npcs.npc_id = quest_npcs.npc_id
WHERE quest_npcs.quest_id = ???
You can even join the quest table into that if you want to get information on the quest in the same query.
SELECT npcs.*, quests.*
FROM quests
INNER JOIN quest_npcs
ON quest_npcs.quest_id = quests.quest_id
INNER JOIN npcs
ON npcs.npc_id = quest_npcs.npc_id
WHERE quest_npcs.quest_id = ???
Or in your case, instead of WHERE quest_npcs.quest_id = ???, use IN() on the quest_id to get a bunch of quests all at once.
SELECT npcs.*, quests.*
FROM quests
INNER JOIN quest_npcs
ON quest_npcs.quest_id = quests.quest_id
INNER JOIN npcs
ON npcs.npc_id = quest_npcs.npc_id
WHERE quest_npcs.quest_id IN(???)

Related

How can I dynamically select a limited number of items using 2 MySQL queries?

On the homepage of my web application I will be displaying a limited number of items. I have 2 queries from 2 different tables in order to display these particular items:
'table1' contains a list of all the items for my application
'table2' contains a column which is used as a reference id to certain items with the same id from 'table1'
This allows me to select which items to display on the homepage.
I have 2 queries:
$t1_items = DB::fetch("SELECT * FROM 'table1'");
$t2_items = DB::fetch("SELECT * FROM 'table2'");
I have 2 foreach loops that run through each table, and compares the id from 'table2' with each item in the 'table1'. If the ids from both tables match, it displays the item on the homepage.
This allows me to select the items I want to display on the homepage by changing the reference id for each item in 'table2'.
Here's my code for the foreach loops:
<?php
foreach ($t1_items as $i => $t1_item) {
foreach ($t2_items as $i => $t2_item) {
if ($t1_item->id == $t2_item->ref_id) {
echo $t1_item->title;
}
}
}
?>
Here's the table structure:
table1: position_name - ref_id
table2: id - title
This code works perfectly fine, the only problem is that it's obviously extremely inefficient since it has to scan through every single item in my database tables in order to grab only a few select items.
Is there a way that I can make $t1_items only dynamically query the items which have the same id the same as each reference id from $t2_items? I need something that is optimised, fast and lightweight in order to support heavy traffic.
Thanks for the help! :)
Have you tried to join the tables into one query?
ie:
select
t1.*
from table1 t1 inner join
table2 t2 on t1.id = t2.ref_id
that will return all rows from table1 that have a row with ref_id=id in table2.
Why not use a subquery in your first query to only pull in items that exist in table2?
$t1_items = DB::fetch("SELECT * FROM 'table1' as t1 WHERE EXISTS (SELECT * FROM 'table2' as t2 WHERE t1.id = t2.ref_id)");
This way you accomplish everything in a single query and let the database do the work.
use following code to get all records from table1 which are also in table2 table as foreign key ref_id
$items = DB::fetch("SELECT * FROM `table1` t1 LEFT JOIN `table2` t2 ON `t2`.ref_id = `t2`.id");
Now, use following loop to loop over all records
<?php
foreach ($items as $i => $item) {
// Displays the item
}
?>

Mysql update one table column based on another table Large amount of data

I am stuck to update one column of table by comparing with another table in php/Mysql. I have tried to speed up the process by indexing the table columns, optimizing the query etc but unable to speed up the process.
In my php based application there is two table (table A and table B) , I want to update one column of table A by comparing with table B (with two column - name & sku).
Previously above process has taken max 15 mints to update 28k products. But now both table (table A and table B) have 60k rows. Now it's taking more than two hours. I have used below query
mysql_query("UPDATE tableA a
JOIN tableB b ON a.product_code_sku = b.sku
SET a.is_existing_product = '1'") or die(mysql_error());
mysql_query("UPDATE tableA a
JOIN tableB b ON a.product_name = b.product_name
SET a.is_existing_product = '1'") or die(mysql_error());
Above query was very slow after that I have changed the updating process like below
$query_result = mysql_query("SELECT t1.`id`,t2.`product_id` FROM `tableA` t1,
`tableB` t2 where (t1.product_code_sku = t2.sku
or t1.product_name = t2.product_name)") or die (mysql_error());
while($result_row = mysql_fetch_array($query_result))
{
mysql_query("UPDATE `tableA` SET is_existing_product = '1'
where id = '".$result_row['id']."' ") or die (mysql_error());
}
But all of my efforts are in vain.
Please advice me how to make the process faster.
Your first update query and the second update query is doing two different thing. The second query is slower because you are using a OR for comparison.
You can consider to create a temporary table to compare and insert, the update back to tableA.
First and all, you should examine the execution for the two join queries, like
desc select a.id
from tableA a
join tableB b ON a.product_code_sku = b.sku;
If this is the reason why the update is slow, you should optimize the query.
Otherwise, you can try the below:
For instance (assuming ID the primary key),
// make sure the columns are in the same data type
create table tmp_sku (
id .. // just the primary key, make sure is using the same data type as in tableA
);
// do a insert into this temporary table
insert into tmp_sku select a.id
from tableA a
join tableB b ON a.product_code_sku = b.sku;
// now we have list of matches,
// then do a insert .. duplicate key update
// by comparing the primary id
insert into tableA (id, is_existing_product)
select tmp_sku.id, 1 from tmp_sku
on duplicate key set is_existing_product = 1;
// repeat for the product name
truncate tmp_sku;
insert into tmp_sku
select a.id
from tableA a
join tableB b ON a.product_name = b.product_name;
// repeat the duplicate .. update
insert into tableA (id, is_existing_product)
select tmp_sku.id, 1 from tmp_sku
on duplicate key set is_existing_product = 1;

PHP/MySQL Using multiple WHEREs in one SELECT query

I have 2 tables.
Table A: trades: which contains the columns: tradeID, tradeName, tradeShow, and tradeGuy.
Table B: offers: which contains the columns: tradeID, offerName, offerGuy.
I'm trying to select all columns from table A (trades) WHERE the value of "tradeShow" = 'Yes', And the value of "tradeGuy" != the user's Username. That much is easy, but I also don't want to select any records which have an offer created by the user. In other words, in table B (offers), offerGuy != Username WHERE trade ID from Table B = tradeID from Table A.
But, how do I merge these 2 conditions? I've tried this:
$sql = "SELECT *
FROM trades t1
JOIN offers t2
ON (t1.tradeID = t2.tradeID)
WHERE t1.tradeShow='Yes' AND t1.tradeGuy!='$username' AND t2.offeringGuy!='$username'";
But the problem with that is it only selects the records from trades which have an offer, because of the forth line: ON (t1.tradeID = t2.tradeID), as in it only selects trades which have a record in (offers) that mentions their tradeID.
I've also tried an awkward attempt to link the 2 tables with a meaningless link by adding a "linker" column to each table with the default value of "XXX", and did this:
$sql = "SELECT *
FROM trades t1
JOIN offers t2
ON (t1.linkerA = t2.linkerB)
WHERE t1.tradeShow='Yes' AND t1.tradeGuy!='$username' AND (t2.offeringGuy!='$username' WHERE t1.tradeID=t2.tradeID)";
But the problem with that is using 2 Where clauses...
So, how do I merge the 2 conditions?
What you're looking for is called an OUTER JOIN (in this case a LEFT OUTER JOIN) which will give you null results for missing matches, something like;
SELECT *
FROM trades t1
LEFT OUTER JOIN offers t2
ON t1.tradeID = t2.tradeID AND t2.offeringGuy = '$username'
WHERE t1.tradeShow='Yes' AND t1.tradeGuy!='$username' AND t2.offeringGuy IS NULL
We add a condition to the LEFT JOIN that we're only interested in matches against t2.offeringGuy = '$username', which will return NULL values in t2's fields if there is no match.
Then we just check that t2.offeringGuy IS NULL to find the non matches.
I would do this with not exists rather than an explicit join:
SELECT *
FROM trades t
WHERE t.tradeShow = 'Yes' AND t.tradeGuy <> '$username' and
not exists (select 1
from offers o
where t.tradeID = o.tradeID and o.tradeGuy = '$username'
);

Records retrieved twice

I have the following php/mySQL code:
$wp_sql_query_text = "SELECT table1.field1, table1.field2, table1.field3,
table2.field1, table2.field2,table3.field1, table3.field2 from table1
INNER JOIN table2 ON table1.field2=table2.field1
INNER JOIN table3 ON table1.field3=table3.field1
WHERE table1.field1 > SOME_VALUE
ORDER BY table1field1";
echo $wp_sql_query_text;
$get_app_history = mysqli_query($conn,$wp_sql_query_text);
$app_entry = mysqli_fetch_assoc($get_app_history);
//some additional code for initialization of counters and variables
while ($app_entry = mysqli_fetch_assoc($get_app_history)){
//some processing
}
Simply put
1) There are 3 tables - table1, table2 and table3.
2) table1 has 3 fields - field1, field2 and field3.
3) table2 and table3 have 2 fields
each.
After 'echo'ing the sql query, I cut and pasted the sql in my phpmyadmin and records are retrieved only once.
However, on my page, I get the same record retrieved twice.
This is because you are fetching your result twice
$app_entry = mysqli_fetch_assoc($get_app_history); // first fetch
.......some additional code for initialization of kounters and variables.....
while ($app_entry = mysqli_fetch_assoc($get_app_history)) // second fetch with a loop
I would suggest to remove first and keep the loop that you might use in case of multiple results

How can I update multiple mysql columns of a row using the result of a select query?

I have a reviews table that contains three ways to rate an item. The items themselves then have three columns to hold the average for each value respectively.
I could do this using three nested queries in an update query, but I feel like this is inefficient... Is there a way to update them all at once?
So far I've used this as my select query:
SELECT AVG(rating_1),AVG(rating_2),AVG(rating_3) FROM items_reviews WHERE item_id = 1
I just don't know how to use the result of that query to update an item row.
You could use an join in the UPDATE:
UPDATE items a
INNER JOIN
(
SELECT
item_id,
AVG(rating_1) AS avg1,
AVG(rating_2) AS avg2,
AVG(rating_3) AS avg3
FROM items_reviews
WHERE item_id = 1
GROUP BY item_id
) b ON a.item_id = b.item_id
SET
a.avgrating1 = b.avg1,
a.avgrating2 = b.avg2,
a.avgrating3 = b.avg3

Categories