How to UPDATE rows in one table where there duplictaes in another - php

I would be massively grateful if someone can help me write a query to update our orders system due to a dupe issue.
We have an orders table and a customers table.
I've identified some duplicate rows in our customers table where the email address and password are the same on unique rows - and are associated with unique live orders by CustomerNumber which exists in each table. This is bad as when a customer logs in to their account, they won't see all of their orders, rather they'll only see the orders associated with the highest customer ID (see login SQL below)
Identify duplicate user accounts:
SELECT
emailaddress,
PASSWORD,
count(*)
FROM
scustomers
JOIN orders ON orders.customernumber = customers.CustomerNumber
WHERE Completed = 1
GROUP BY
emailaddress,
PASSWORD
HAVING
count(*) > 1
Login SQL:
SELECT * FROM scustomers WHERE EmailAddress = :EmailAddress AND (Password = :Password) ORDER BY CustomerNumber DESC LIMIT 0,1
I need to write a query that:
Updates the "orders" table
Updates the "CustomerNumber" column
Sets the "CustomerNumber" column to be the highest "CustomerNumber"
WHERE the "customers" table has more than 1 rows with has an
identical "Email" and "Password" column
Where do I start?!
Our system has been fixed so that any customer order a new product by logging in will always use the highest possible associated CustomerNumber so this really is about fixing existing data.
UPDATE:
I've never used SQL Fiddle, but here is some sample data that I hope will help you.. help me!
CUSTOMERS:
customernumber, email, password
3272, jwilson#email.com, 9a098e0bade9b4f2ac4ecdf86111cf7e
10001, jwilson#email.com, 9a098e0bade9b4f2ac4ecdf86111cf7e
ORDERS:
ordernumber,customernumber,status
123457, 3272, 'LIVE'
123456, 10001, 'LIVE'
I need to update OrderNumber: 123457 to have the CustomerNumber of 10001, not 3272.

Step 1 : create a temporary column to store the correct CustomerNumber
ALTER TABLE scustomers
ADD COLUMN id_tmp INT NOT NULL;
Step 2 : retrieve the correct CustomerNumber
UPDATE scustomers
INNER JOIN
(
SELECT
emailaddress,
PASSWORD,
MAX(CustomerNumber) AS id
FROM
scustomers
GROUP BY
emailaddress,
PASSWORD
) AS duplicate ON scustomers.emailaddress = duplicate.emailaddress AND scustomers.PASSWORD = duplicate.PASSWORD
SET id_tmp = id;
Step 3 : update order table with the correct CustomerNumber
UPDATE orders
INNER JOIN scustomers ON orders.customerNumber = customers.CustomerNumber
SET orders.customernumber = id_tmp;
Step 4 : delete duplicate customers
DELETE FROM scustomers
WHERE customernumber <> id_tmp;
Step 5 : remove the temporary column
ALTER TABLE scustomers
DROP COLUMN id_tmp;

I am just giving idea about sql query you need to write for loop
SELECT GROUP_CONCAT( customernumber) , i.email
FROM scustomers i INNER JOIN ( SELECT k.email FROM scustomers k GROUP BY k.email
HAVING COUNT( `customernumber` ) >1 )j ON i.email = j.email GROUP BY i.email
Out put :
----------------------------
customernumber Email
---------------------------
1,2,3 ss#ss.ss
After this all duplicate will come in on field.explode the new customernumber get last value in that array (Ex: 3 is last value)
update `orders` set `customernumber`='last array value(Ex: 3)' WHERE `customernumber` in (customernumber from above query(1,2,3) )
For delete duplicate records
DELETE n1 FROM scustomers n1, scustomers n2 WHERE n1.customernumber< n2.customernumber AND n1.email= n2.email

Related

How to insert data into new table from other table and make sum of two column

I am using below mysql query to insert data from oldtable to newtable after the user ads money to his account. if user credit some money to his account i want to enter the value of accbal column to be the sum of credit column value and accbal (user older account balance). i.e i want to add mysql row having user account resultant balance after adjusting debit credit amount. Kindly tell me how to do it with mysql and php.
$sql2="INSERT INTO newtable (emailadd, credit, debit, accbal, txtime, txnid) SELECT buyeremailaddr, 'balcredit', '0', QUESTION, pptxtime, pptxid FROM oldtable WHERE paymenthash='$item_no' AND paid='1'";
$result2=mysql_query($sql2);
this is probably more complex than you need, but it gets tricky when you're trying to link in the value from the related record with the most recent date:
INSERT INTO newtable (
emailadd
, credit
, debit
, accbal
, txtime
, txnid
) SELECT buyeremailaddr
, 'balcredit'
, '0'
, credit + accbal
, pptxtime
, pptxid
FROM oldtable
LEFT JOIN (
SELECT emailadd,accbal FROM newtable JOIN (
SELECT emailadd
,MAX(txtime) AS maxdate
FROM newtable GROUP BY emailadd
) AS mt ON mt.maxdate = newtable.txtime
AND mt.emailadd = newtable.emailadd GROUP BY emailadd
) AS nt ON oldtable.buyeremailaddr = nt.emailadd
WHERE paymenthash='$item_no'
AND paid='1'
essentially you join to the newtable grouped by email, which is in turn joined to itself again grouped by email in order to compare the txtime to the max txtime to get the most recent accbal value. warning: this does not scale well with very large tables. better to create views, or even better, reassess your existing data structure

What type of index should I to add on a multiple request_id in mysql

Data are taking too much time to load when I am searching with specified date. In my project has two table, In one table has unique entries and I added unique index to "request_id" and primary index to auto incremented "id" . another table have multiple records with request_id and in that I added only a primary index to auto incremented "id". Now I am to search these all record through join in both table to check the count for a every "request_id".
I am using below query:-
SELECT
m.id,m.request_id as id,count(m.request_id) as count,m.reqtype,m.request_time,w.status as status,w.updated_time as updated_time,w.reg_date as reg_date
FROM
multi_requests m JOIN unique w ON m.request_id = w.request_id
WHERE
m.request_time
Between
'2015-07-05'
AND
'2015-07-06'
GROUP BY
m.request_id
ORDER BY
m.id asc
LIMIT
0,10" ;
I also try to add index to "request_id" in multi_requests table. But when I am adding Index to "request_id" and searching with above query its not showing any type of records on UI.
In multi_requests table has total records = 6033030.
So please suggest me..
This is your query:
SELECT m.id, m.request_id as id, count(m.mac_address) as count, m.reqtype,
m.request_time, w.status as status, w.updated_time as updated_time,
w.reg_date as reg_date
FROM multi_requests m JOIN
unique w
ON m.mac_address = w.mac_address
WHERE m.request_time Between '2015-07-05' AND '2015-07-06'
GROUP BY m.request_id
ORDER BY m.id asc
LIMIT 0, 10 ;
It is a bit strange, because you have a ton of columns in the select, but only one in the group by. Let me assume that you know what you are doing.
For this query, the best indexes are on multi_requests(request_time, mac_address, request_id) and unique(mac_address).

MySql - if there is no record, insert multiple rows

Before asking this question, I already search a lot of entries on Google and StockOverflow. Nothing can fulfil my question.
There are two tables - group_sale_bonuses and members. I want to check is already there records with product_id "1" in the group_sale_bonuses.
If not, I want to insert all records from members table into group_sale_bonuses with product_id "1".
My overall requirement is as follow:
IF ((Select count(id) from group_sale_bonuses where product_id = 1) = 0) THEN
INSERT INTO group_sale_bonuses (member_id, product_id, quantity_counter, credit)
SELECT id, 1, 0, 0 FROM members
END IF
But this sql causes the errors.
I know there are solutions about Insert Ignore, Where Not Exists.
But these conditions checking are based on per each record. I have thousands of records in members table. I want to make condition checking just one time like in my above sql example.
By the way, I will use this Sql in Php web application.
You could just set the code in a WHERE clause instead of the IF.
INSERT INTO group_sale_bonuses(
member_id,
product_id,
quantity_counter,
credit)
SELECT
id, 1, 0, 0 FROM members
WHERE(
SELECT
count(id) FROM group_sale_bonuses
WHERE product_id = 1
) = 0;
This should do it for all product_id's
SELECT m.product_id, m.member_id FROM members AS m
LEFT JOIN group_sale_bonuses AS gsb ON gsb.product_id = m.product_id
WHERE gsb.product_id IS NULL ;
You can filter it to a specific product_id by adding to the where clause
SELECT m.product_id, m.member_id FROM members AS m
LEFT JOIN group_sale_bonuses AS gsb ON gsb.product_id = m.product_id
WHERE gsb.product_id IS NULL AND m.product_id = 1;
Take a look at this SQLfiddle: http://sqlfiddle.com/#!2/8482c/2

update (or insert) multiple rows in one query

I am trying to update multiple rows in a table at once (or insert them if they do not exist) given settings and an array of user id's.
An example of how I select all rows from the settings table for all users of specific computers of a specific account. This is the result set which I need to insert values in or update if they exist.
$stmt = $db->prepare("
SELECT settings.*
FROM
( SELECT account_id, computer_id
FROM computers
ORDER BY computer_id ASC LIMIT 0, ".$_SESSION['user']['licenses']."
) as c
LEFT JOIN users
on users.computer_id = c.computer_id
LEFT JOIN accounts
on accounts.account_id = c.account_id
LEFT JOIN settings
on settings.user_id = users.user_id
WHERE accounts.account_id = ".$_SESSION['user']['account_id']."
");
What I am trying to do :
I am trying to update/insert three columns (enabled, status, and user_id) in the settings table for only those user ids listed in the array. Enabled and status values will be the same for all, but the user_id will be different for each.
$users = array(12, 36, 43, 56, 76)
$binding = array(
'enabled' => 1,
'status' => 2,
'user_id' => from the array
);
If my thought process is correct I can create a virtual table from my statement listed above then use ON DUPLICATE KEY UPDATE to insert/update on the results of that virtual table?
Is this possible? If so, example, tips, or point in the right direction? The way I have working involves a foreach loop for each user id in the given array so there will be x number of queries depending on its count. If I can cut that to only one that would be great!
UPDATE:
Ok, I am totally confused now... this is an attempt for defined values which is not working... and I still need a way to do so for every user_id in my array as mentioned above. Don't I need to 'save' my entire FROM clause AS a new reference as well?
$stmt = $db->prepare("
INSERT INTO settings (user_id, enabled, status)
VALUES (:user_id, :enabled, :alert_user)
SELECT user_id, enabled, status
FROM
( SELECT account_id, computer_id
FROM computers
ORDER BY computer_id ASC LIMIT 0, ".$_SESSION['user']['licenses']."
) as c
LEFT JOIN users
on users.computer_id = c.computer_id
LEFT JOIN accounts
on accounts.account_id = c.account_id
LEFT JOIN settings
on settings.user_id = users.user_id
WHERE accounts.account_id = ".$_SESSION['user']['account_id']."
ON DUPLICATE KEY UPDATE enabled = VALUES(enabled), status = VALUES(status)
");
$binding = array(
'enabled' => 1,
'alert_user' => 4,
'user_id' => 6
);
$stmt->execute($binding);
Yes, your thinking is correct. It should be something like this:
INSERT INTO settings (user_id, enabled, status)
SELECT user_id, enabled, status
FROM ... -- rest of your query here
ON DUPLICATE KEY UPDATE enabled = VALUES(enabled), status = VALUES(status)
VALUES(colname) in the ON DUPLICATE KEY UPDATE clause gets the value that would have been inserted if there hadn't been a dupliate.
OK, based on your comment, I think this may be what you want:
INSERT INTO settings (user_id, enabled, status)
SELECT :user_id, :enabled, :status
FROM ...
JOIN ...
JOIN ...
WHERE ...
ON DUPLICATE KEY UPDATE enabled = VALUES(enabled), status = VALUES(status)
If the join returns any rows, this will insert or update the specified row. If it doesn't find any rows, no insert/update will be done.
You should probably be using inner joins rather than left joins, if you don't want anything returned when there are no matches in the tables being joined with.

Getting random record from database with group by

Hello i have a question on picking random entries from a database. I have 4 tables, products, bids and autobids, and users.
Products
-------
id 20,21,22,23,24(prime_key)
price...........
etc...........
users
-------
id(prim_key)
name user1,user2,user3
etc
bids
-------
product_id
user_id
created
autobids
--------
user_id
product_id
Now a multiple users can have an autobid on an product. So for the next bidder I want to select a random user from the autobid table
example of the query in language:
for each product in the autobid table I want a random user, which is not the last bidder.
On product 20 has user1,user2,user3 an autobidding.
On product 21 has user1,user2,user3 an autobidding
Then I want a resultset that looks for example like this
20 – user2
21 – user3
Just a random user. I tried miximg the GOUP BY (product_id) and making it RAND(), but I just can't get the right values from it. Now I am getting a random user, but all the values that go with it don't match.
Can someone please help me construct this query, I am using php and mysql
The first part of the solution is concerned with identifying the latest bid for each product: these eventually wind up in temporary table "latest_bid".
Then, we assign randon rank values to each autobid for each product - excluding the latest bid for each product. We then choose the highest rank value for each product, and then output the user_id and product_id of the autobids with those highest rank values.
create temporary table lastbids (product_id int not null,
created datetime not null,
primary key( product_id, created ) );
insert into lastbids
select product_id, max(created)
from bids
group by product_id;
create temporary table latest_bid ( user_id int not null,
product_id int not null,
primary key( user_id, product_id) );
insert into latest_bid
select product_id, user_id
from bids b
join lastbids lb on lb.product_id = b.product_id and lb.created = b.created;
create temporary table rank ( user_id int not null,
product_id int not null,
rank float not null,
primary key( product_id, rank ));
# "ignore" duplicates - it should not matter
# left join on latest_bid to exclude latest_bid for each product
insert ignore into rank
select user_id, product_id, rand()
from autobids a
left join latest_bid lb on a.user_id = lb.user_id and a.product_id = lb.product_id
where lb.user_id is null;
create temporary table choice
as select product_id,max(rank) choice
from rank group by product_id;
select user_id, res.product_id from rank res
join choice on res.product_id = choice.product_id and res.rank = choice.choice;
You can use the LIMIT statement in conjunction with server-side PREPARE.
Here is an example that selects a random row from the table mysql.help_category:
select #choice:= (rand() * count(*)) from mysql.help_category;
prepare rand_msg from 'select * from mysql.help_category limit ?,1';
execute rand_msg using #choice;
deallocate prepare rand_msg;
This will need refining to prevent #choice becoming zero, but the general idea works.
Alternatively, your application can construct the count itself by running the first select, and constructing the second select with a hard-coded limit value:
select count(*) from mysql.help_category;
# application then calculates limit value and constructs the select statement:
select * from mysql.help_category limit 5,1;

Categories