SQL INSERT from SELECT producing duplicate records - php

I'm learning PHP and Zend Framework. The following PHP function is supposed to fill a temporary table using "INSERT INTO ... SELECT" style query. However, when I SELECT * from the newly appended table, I see that most but not all of the new records have been duplicated once. I have deleted the contents of the table each time I run this scripts. Anyone know why there would be duplicates?
public function fillTableByOfficeName($officeName) {
if ($officeName != '') {
$officePhrase = "b.oof_name ='" . $officeName . "' AND ";
} else {
$officePhrase = '';
}
$whereAddenda = $officePhrase .
"a.fil_bool_will_file_online = false AND " .
"a.fil_bool_confirmed = false AND " .
"a.fil_bool_duplicate = false AND " .
"a.fil_bool_not_found = false AND " .
"(a.fil_res_id_fk NOT IN (4,7,10) OR a.fil_res_id_fk IS NULL) AND " .
"a.fil_will_recorder_rec_id IS NULL AND " .
"d.tag_description NOT IN (
'Already a trust client',
'Not received from local office',
'Southtrust client (already centralized)')";
//"a.fil_date_of_transfer_to_will_recorder IS NULL";
$sql = "INSERT INTO adds(fil_id,REC_ID,FIRST_NAME,LAST_NAME,MIDDLE_INITIAL,SSN," .
"MAILING_ADDRESS_1,MAILING_ADDRESS_2,CITY,STATE,ZIP_CODE,PHONE_NUMBER,BIRTH_DATE," .
"ORIGINATION_OFFICE,FILE_LOCATION,WILL_DATE,LAST_CODICIL_DATE,TRUST_DATE,REV_TRUST,POA_DATE) " .
"SELECT a.fil_id_pk, " .
"a.fil_will_recorder_rec_id, " .
"a.fil_first_name, " .
"a.fil_last_name, " .
"a.fil_middle_name, " .
"a.fil_ssn, " .
"a.fil_mailing_address_1, " .
"a.fil_mailing_address_2, " .
"a.fil_city_address, " .
"a.fil_state_address, " .
"a.fil_zip_code_fk, " .
"a.fil_phone_number, " .
"a.fil_date_of_birth, " .
"b.oof_name, " .
"a.fil_box_id_fk, " .
"a.fil_date_of_will, " .
"a.fil_date_of_last_codicil, " .
"a.fil_date_of_trust, " .
"a.fil_notes, " .
"a.fil_date_of_poa " .
"FROM files a, origination_offices b, nn_files_tags c, tags d " .
"WHERE " .
"a.fil_oof_id_fk = b.oof_id_pk AND " .
"a.fil_id_pk = c.fil_id_fk AND " .
"d.tag_id_pk = c.tag_id_fk AND " .
$whereAddenda;
$this->getAdapter()->query($sql);
return $this;
}

The way you are joining the table will give you the cartesian product of the rows from the tables (all pairs of matching rows are returned).
With no specific knowledge of the domain, I would guess at the tags table - if you've got multiple tags for a particular file, you will get multiple copies of the file in your result set (one per each matched tag).
As you're not using tags fields in the result set, just the where clause, the solution would be to get rid of tags / nn_files_tags from the main query, and in your where clause, use NOT EXISTS to check for matching rows in the tags table, something like:
AND NOT EXISTS (SELECT tag_id_pk FROM tags WHERE tags.tag_id_pk ...

You are using C for a many to many relationship. For example, if you have invoices between companies and customers and you select from join of them, you will get as many rows as you have invoices. From that, if you only select the company name and costumer name, you will have many duplicates because the same pair has produced many invoices.
This is the same issue you have here.
As asc99c said, you could use an inner select to make your WHERE clause without joining on that relationship or you could use the DISTINCT key word (which effectively is a group by on everything in your SELECT clause). I would think the INNER SELECT solution more efficient (yet I could be totally wrong about that), but the DISTINCT way is 8 key press away...

Related

Return query with missing/different data only

i have a form where you can select category and will return products that are in this category
$query = $this->db->query("SELECT id, name FROM " . DB_PREFIX . "shared_products_product WHERE category = '" . (int)$id . "' AND status != 2");
Result
Array
(
[0] => Test 1
[1] => Test 2
[2] => Test 3
)
Than you can select only Test 1 and Test 2 to insert in different table
$this->db->query("INSERT INTO " . DB_PREFIX . "shared_products_view SET product_id = '" . (int)$product_id . "', shared_product_id = '" . (int)$shared_product_id . "', category_id = '" . (int)$cat_id . "'");
When i run 1st query how will i get result that still not inserted into shared_products_view for current category_id ?
you need to join table and check if value is already existing
Like this
$query = $this->db->query("SELECT `spp`.id, `spp`.name
FROM " . DB_PREFIX . "shared_products_product `spp`
LEFT JOIN " . DB_PREFIX . "shared_products_view `spv` ON `spp`.`id`=`spv`.shared_product_id
WHERE category = '" . (int)$id . "' AND status != 2 AND `spv`.shared_product_id IS NULL");
When you run your second query, the INSERT, the row will be added, unless you have an error. One thing that comes to mind is you seem to insert integers as strings.
It is better to use PDO and bindValue() and explicitly state it is an integer.
If I understand you right, you want to know if the INSERT succeeded. (Is that correct?)
In that case check the result of your command $this->db->query("INSERT ...").
You didn't mention what database handle $this->db is, but I expect it will return false on failure.
I highly recommend you study this hands-on guide first before proceeding:
https://phpdelusions.net/pdo

sql left join not working

I want to get total transfered items from table inv_site_item where 'item_id' in inv_sie_item = 'item_code' in inv_items, I am getting packing also from packing table which works fine in this query only inv_site_item is giving problem.
error is: Unknown column 'inv_site_item.site_id' in 'field list'
$where .= " AND inv_items.item_code = $item_code";
$query = "SELECT inv_items.*,packing.name_en `packing_name`,"
. " COUNT(inv_site_item.site_id) `transfer_out`, COUNT(inv_site_item.location_site_id) `transfer_in` FROM inv_items"
. " left join "
. "inv_packing as packing on packing.id=inv_items.packing"
. " left join "
. "inv_site_item as transfer on transfer.item_id=inv_items.item_code"
. " WHERE item_code !='' " . $where . "";
you must use your table alias transfer instead, So:
change from
inv_site_item.site_id
to
transfer.site_id
also with inv_site_item.location_site_id to be transfer.location_site_id
For any query related errors you should always check to print the query if possible. Your "WHERE" clause is not getting populated correctly.
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE item_code !=''' at line 1
This means that your query is giving error near your "WHERE" clause.
Print your $query variable to see the actual query that is built then you will be able to find the error and fix it.
<?php echo "<pre>"; print_r($query); echo "</pre>"; ?>
you must use your table alias transfer instead, So:
change from
inv_site_item.site_id
to
transfer.site_id
also with inv_site_item.location_site_id to be transfer.location_site_id
And also change $where .= " AND inv_items.item_code = $item_code"; to
$where .= "inv_items.item_code = $item_code";
and
change query statement to
$query = "SELECT inv_items.*,packing.name_en `packing_name`,"
. " COUNT(transfer.site_id) `transfer_out`, COUNT(transfer.location_site_id) `transfer_in` FROM inv_items"
. " left join "
. "inv_packing as packing on packing.id=inv_items.packing"
. " left join "
. "inv_site_item as transfer on transfer.item_id=inv_items.item_code"
. " WHERE " . $where . " AND item_code !=' '";
For let not empty clause come at last...

Is it possible to combine these two SQL statements into one?

I am using these two MySQL statements to get all messages between two users, but I am running into a pretty big problem when it comes to manipulating the data later in the code since it's not in order by ID. Is there any way to combine these statements AND order the results by ID?
$sql = "SELECT * FROM messages WHERE sender='" . $username . "' AND receiver='" . $chatPartner . "'"
$sqlTwo = "SELECT * FROM messages WHERE sender='" . $chatPartner . "' AND receiver='" . $username . "'"
Essentially, I need every occurrence of a message between two people, but sorted by ID. As of right now, I am joining the arrays to get my full list, but it's not in order by ID.
SELECT * FROM messages
WHERE (sender='" . $username . "' AND receiver='" . $chatPartner . "'")
OR (sender='" . $chatPartner . "' AND receiver='" . $username . "'")
ORDER BY id DESC
How about just combine both into 1 query ?
$sql = "SELECT * FROM messages WHERE (sender=" . $username . " OR sender =". $chatPartner .") AND (receiver=" . $chatPartner . " OR receiver=" . $username .") ORDER BY id"
You could also write a shorter version of #dtj's answer using row constructors.
SELECT *
FROM messages
WHERE (sender, receiver) IN (($username, $chatPartner),($chatPartner, $username))
ORDER BY id DESC
In my opinion it looks a bit nicer in code and makes it more readable, but remember that it doesn't improve performance of execution.

Error: Column 'id' in field list is ambiguous php mysqli

I have two table :
news:
|id|title|image|timestamp|....
tags:
|id|books_id|...
for result:
("SELECT id,title,front_thumbs,short_desc,timestamp,counter,author,
FROM " . NEWS . " LEFT JOIN " . TAGS . " ON " NEWS . ".id = " . TAGS . ".content_id WHERE
" . TAGS . ".tags_id = ? AND approved = 1 ORDER BY timestamp DESC LIMIT 10", $id)
but I see this error:
Error: Column 'id' in field list is ambiguous
how do fix this error?
When both tables have same field name it gets ambiguous and to solve this
use SELECTNEWS.id or TAGS.id which table's id you are using:
"SELECT NEWS.id,title,front_thumbs,short_desc,timestamp,counter,author,
FROM " . NEWS . " LEFT JOIN " . TAGS . " ON " NEWS . ".id = " . TAGS . ".content_id WHERE
" . TAGS . ".tags_id = ? AND approved = 1 ORDER BY timestamp DESC LIMIT 10", $id)
You need alias. Yuo have 2 tables both with column id. In your select you request id without specifying which of them you need.
You need to specify table here (before id):
... ("SELECT id,title,front_thumbs,short ...

PHP JOIN Two MySQL table in result

I have two MySQL table for insert comment data and reviews data like this :
comments:
|id|post_id|text|name|timestamp|approved|parent_id|type|ip|
reviews:
|id|postID|comments_id|reviewfield1|reviewfield2|reviewfield3
in action I insert for each comments One reviews. Now, I need to show/print comment list with comment name and text + reviewfield1 reviewfield2 reviewfield3 for each comments where comments is approved like this :
commenter 1
text
reviewfield1
reviewfield2
reviewfield3
TRY:
"SELECT name,text,timestamp FROM " . COMMENTS . " LEFT JOIN " . REVIEWS . " WHERE " . COMMENTS . ".id = " . REVIEWS . ".comments_id AND
post_id = ? AND type = ? AND approved = 1 ", $id, $type"
But this not work for me. how do generate this with PHP JOIN method?
You are making mistake in the query. It must be like this:
"SELECT name,text,timestamp,reviewfield1 FROM " . COMMENTS . " LEFT JOIN " . REVIEWS . " ON " . COMMENTS . ".id = " . REVIEWS . ".comments_id WHERE
post_id = ? AND type = ? AND approved = 1 ", $id, $type"
And you can select rows from the second(joined) table, same as the first one.

Categories