Is it possible to merge these queries? - mysql

Is it possible to merge these queries?
$sql1 = "UPDATE users AS u, invites AS i
SET u.uinvite = u.uinvite - 1, u.ufriends = CONCAT(u.ufriends, ',$iid'), i.seen = 1
WHERE u.uid = '$uid' AND i.invited_uid = '$uid' AND i.invitor_uid = '$iid'";
$sql2 = "UPDATE users
SET ufriends = CONCAT(ufriends, ',$uid')
WHERE uid = '$iid'";
Variable explanation:
$uid = the users ID $iid = the friends ID
This was my attempt to merge:
$mergesql = "UPDATE invites AS i, users AS u
SET
CASE
WHEN u.uid = '$uid' THEN u.uinvite=u.uinvite-1, u.ufriends = CONCAT(u.ufriends,',$iid')
ELSE u.ufriends = CONCAT(u.ufriends,',$uid')
END
, i.seen = '1'
WHERE i.invited_uid = '$uid' AND i.invitor_uid = '$iid'
AND (u.uid = '$uid' OR u.uid = '$iid')"
I find it hard to understand how mysql works when you have to do more complicated queries.
My English also lacks expertise, if you know a good tutorial, you can make me really happy with it! (not the one from the MySQL website, it's killing =S)

Knowing MySQL, there is probably a way to do this in one query, but I don't think you would get any benefit at all because you are updating based on totally separate keys. It might actually be dangerous to do this because the result would be unpredictable. Doing it in two queries, it's easy to figure out what's going on.
If it's not too late, I would suggest that you remove the friends field in favor of a mapping table between users and friends.

Did you try this:
$mergesql = "UPDATE
users AS u,
invites AS i,
users AS uf
SET
u.uinvite = u.uinvite - 1, u.ufriends = CONCAT(u.ufriends, ',$iid'),
i.seen = 1,
uf.ufriends = CONCAT(uf.ufriends, ',$uid')
WHERE u.uid = '$uid'
AND i.invited_uid = '$uid' AND i.invitor_uid = '$iid'
AND uid = '$iid'";
?

Related

Updating a table of 10k records efficiently in MYSQL

I have two tables, Table A and Table B. Table A has 10k records. Table B has those 10K old records and additional records. I need to update the old 10k records in Table B.
I used,
UPDATE CONTENT_WORKFLOW_MASTER CWM, CWSCOPY TMP SET
CWM.PROGRAM_ID = TMP.PROGRAM_ID,
CWM.PROGRAM_TYPE_ID = TMP.PROGRAM_TYPE_ID,
CWM.PROGRAM_TYPE_NAME = TMP.PROGRAM_TYPE_NAME,
CWM.ORIGINAL_TITLE = TMP.ORIGINAL_TITLE,
CWM.SOURCE_GROUP_ID = TMP.SOURCE_GROUP_ID,
CWM.MASTER_TITLE = TMP.MASTER_TITLE,
CWM.PROGRAM_LANGUAGE = TMP.PROGRAM_LANGUAGE,
CWM.REGION = TMP.REGION,
CWM.CW_STATUS = 'NEW',
CWM.COPY_CULTURE = TMP.COPY_CULTURE,
CWM.GENRES = TMP.GENRES,
CWM.AIR_DATE_TIME = TMP.AIR_DATE_TIME,
CWM.PROCESS_ID = TMP.GUID,
CWM.PRIORITY = 0,
CWM.UPDATED_BY_SCHEDULE = 1,
CWM.MODIFIED_USER = 'StoredProcUser',
CWM.MODIFIED_DATE = NOW() WHERE CWM.PROGRAM_ID = TMP.PROGRAM_ID ;
And i used,
UPDATE CONTENT_WORKFLOW_MASTER CWM INNER JOIN t.temp TMP
USING (PROGRAM_ID)
SET
CWM.PROGRAM_ID = TMP.PROGRAM_ID,
CWM.PROGRAM_TYPE_ID = TMP.PROGRAM_TYPE_ID,
CWM.PROGRAM_TYPE_NAME = TMP.PROGRAM_TYPE_NAME,
CWM.ORIGINAL_TITLE = TMP.ORIGINAL_TITLE,
CWM.SOURCE_GROUP_ID = TMP.SOURCE_GROUP_ID,
CWM.MASTER_TITLE = TMP.MASTER_TITLE,
CWM.PROGRAM_LANGUAGE = TMP.PROGRAM_LANGUAGE,
CWM.REGION = TMP.REGION,
CWM.CW_STATUS = 'NEW',
CWM.COPY_CULTURE = TMP.COPY_CULTURE,
CWM.GENRES = TMP.GENRES,
CWM.AIR_DATE_TIME = TMP.AIR_DATE_TIME,
CWM.PROCESS_ID = TMP.GUID,
CWM.PRIORITY = 0,
CWM.UPDATED_BY_SCHEDULE = 1,
CWM.MODIFIED_USER = 'StoredProcUser',
CWM.MODIFIED_DATE = NOW() WHERE CWM.USER_LOCKED=0;
create TEMPORARY table t.temp AS
SELECT DISTINCT CWS.CONTENT_WORKFLOW_STAGING_ID,CWS.PROGRAM_ID,CWS.SOURCE_GROUP_NAME,CWS.COPY_CULTURE,
CWS.PROGRAM_TYPE_ID, CWS.PROGRAM_TYPE_NAME, CWS.ORIGINAL_TITLE, CWS.SOURCE_GROUP_ID, CWS.MASTER_TITLE,
CWS.PROGRAM_LANGUAGE, CWS.REGION, CWS.GENRES, CWS.AIR_DATE_TIME, CWS.GUID,CWS.IS_PROCESSED, CWS.INTERNAL_TRANSACTION_ID
FROM CONTENT_WORKFLOW_STAGING CWS INNER JOIN CONTENT_WORKFLOW_MASTER CWM ON
CWM.PROGRAM_ID = CWS.PROGRAM_ID AND
CWM.SOURCE_GROUP_NAME = CWS.SOURCE_GROUP_NAME AND CWM.COPY_CULTURE = CWS.COPY_CULTURE AND CWM.USER_LOCKED = 0
AND
CWS.IS_PROCESSED = 0 AND CWS.INTERNAL_TRANSACTION_ID = INTERNAL_TRANSACTION_ID;
Both the queries are not full efficient. CAn anyone suggest the efficient way to to that. Within atleast 10 sec.

sql update statement with from clause for validation?

I have an update operation that I perform on multiple users at once (the value stays the same). Is it possible to join tables to an update statement for reasons of validation?
For instance, here is my statement at the moment :
$user_set = array(1, 5, 10, 15, .....)
//update 'changed' status for ALL selected users at once
$stmt = $db->prepare("
UPDATE users
SET changed = ?
WHERE user_id IN(". implode(', ', array_fill(1,count($user_set),'?')) .")
");
array_unshift($user_set, 1);
$stmt->execute($user_set);
In a perfect scenario I would like to join one table (computers) to the users table to validate account ownership and if this update is 'valid' and should occur or not.
I found out earlier I can do EXACTLY that with DELETE, but can it be done with UPDATE as well? Example delete using validation I want :
$selected = array(1, 5, 10, 15, .....)
$stmt = $db->prepare("
DELETE del_table.*
FROM some_table as del_table
LEFT JOIN
users
on users.user_id = del_table.user_id
LEFT JOIN
computers
on computers.computer_id = users.computer_id
WHERE computers.account_id = ? AND del_table.activity_id IN(". implode(', ', array_fill(1,count($selected),'?')) .")
");
// use selected array and prepend other data into the array so binding and execute work in order
array_unshift($selected, $_SESSION['user']['account_id']);
$stmt->execute($selected);
EDIT (SOLUTION) :
Thanks Alex... it works!
$selected = array(5,10,12,13);
$stmt = $db->prepare("
UPDATE users
INNER JOIN computers
on computers.computer_id = users.computer_id
SET changed = ?
WHERE computers.account_id = ? AND users.user_id IN(". implode(', ', array_fill(1,count($selected),'?')) .")
");
array_unshift($selected, 1, $_SESSION['user']['account_id']);
$stmt->execute($selected);
Yes, you can, as documented here under the multi-table syntax section.
UPDATE [LOW_PRIORITY] [IGNORE] table_references
SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
[WHERE where_condition]
You just need to make sure you order the statements correctly.
UPDATE my_table
INNER JOIN other_table
ON my_table.col2 = othertable.col2
SET my_table.col = 'foo'
WHERE other_table.col = 'bar'
try this
$stmt = $db->prepare("
UPDATE users
SET changed = ?
from users
JOIN computers on computers.computer_id = users.computer_id
WHERE user_id IN(". implode(', ', array_fill(1,count($user_set),'?')) .")
");

Optimizing MySQL operation to get counts

I have this lovely piece of code that copies out different counts of rows so I can build an associative list of how many of each good a citizen possesses.
$citizen_id = 1;
$goods = array();
$goods_result = mysql_query("SELECT id,name FROM goods");
while(($goods_row = mysql_fetch_assoc($goods_result))) {
$good_id = $goods_row['id'];
$query = "SELECT count(*) FROM possessions where citizen_id=$citizen_id and good_id=$good_id";
$possessed_result = mysql_query($query);
$possessed_row = mysql_fetch_row($possessed_result);
if($possessed_row) {
$possessed = $possessed_row[0];
$goods[$goods_row['name']] = $possessed;
}
}
echo json_encode ($goods);
It works, but it runs too slow. It seems to me that there must be a way to get MySQL to build a table of counts and return it to me in a single query, but I have no idea how to figure out how to do that. Any ideas on how to make this operation faster?
How about using a query like
SELECT g.id good_id,
count(*) cnt_of_goods
FROM possessions p INNER JOIN
goods g ON p.good_id = g.id
where citizen_id=$citizen_id
GROUP BY g.id

Writing a custom mysql query to order wordpress users by a custom user meta field

Basically, I need to order a list of WordPress users by the city they live in. I've got a custom user meta field for city, and I've got the query working properly, but the query lists everyone who hasn't filled out a city at the beginning since it places blank fields at the beginning of the order.
What I need is to figure out how to only select and display users who have given a value other than blank in the city field. Unfortunately, I've found myself stumped.
Any thoughts on how to do this? Also, if anyone knows a way to orderby a custom user meta field using wp_user_query as opposed to this mess, I'm all ears.
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
$limit = 10;
$offset = ($paged - 1) * $limit;
$key = 'city';
$sql = "SELECT SQL_CALC_FOUND_ROWS {$wpdb->users}.* FROM {$wpdb->users}
INNER JOIN {$wpdb->usermeta} wp_usermeta ON ({$wpdb->users}.ID = wp_usermeta.user_id)
INNER JOIN {$wpdb->usermeta} wp_usermeta2 ON ({$wpdb->users}.ID = wp_usermeta2.user_id)
WHERE 1=1
AND wp_usermeta.meta_key = 'wp_capabilities'
AND CAST(wp_usermeta.meta_value AS CHAR) LIKE '%\"subscriber\"%'
AND wp_usermeta2.meta_key = '$key'
ORDER BY wp_usermeta2.meta_value ASC
LIMIT $offset, $limit";
$site_users = $wpdb->get_results($sql);
$found_rows = $wpdb->get_var("SELECT FOUND_ROWS();");
foreach ($site_users as $site_user) {
// user info here
}
Try something like
...
WHERE 1=1
AND wp_whatever.name_of_city IS NOT NULL
AND LENGTH(wp_whatever.name_of_city) > 0
AND wp_usermeta.meta_key = 'wp_capabilities'
...

Writing a MYSQL Following Users Query

I'm building an app where a user can follow other users and be followed.
A user can also look at who another user is following.
Now lets say user1 is looking at who user2 is following, I need to find all the people IDs that user2 is following and compare it against who user1 is following.
Instead of returning only the IDs of all the users that match both user1 and user2 (which I've seen in other forums), I need to retrieve all user2's following IDs and User Names as well as a flag that indicates if the followed person is also followed by user1.
I've got it to work in PHP with a double for loop of each Query, but I worry that this code will be expensive and would be far better optimized with a single MYSQL query.
Relevant tables and columns:
following_table
follower_id
followed_id
following: varchar -- 'true' or 'false'
user_table
user_id
user_name
Here is my PHP code:
$user_id1 = '1991';
$myFollowingQuery = "SELECT following_table.followed_id, user_table.user_name
FROM following_table
INNER JOIN user_table ON
following_table.followed_id = user_table.user_id
WHERE following_table.following = 'true'
AND following_table.follower_id = '$user_id1'";
$user_id2 = '1985';
$userFollowingQuery = "SELECT following_table.followed_id, user_table.user_name
FROM following_table
INNER JOIN user_table ON
following_table.followed_id = user_table.user_id
WHERE following_table.following = 'true'
AND following_table.follower_id = '$user_id2'";
$userFollowingResult = mysql_query($userFollowingQuery)
or doResponse('error',"Couldn't connect to the database");
$myFollowingResult = mysql_query($myFollowingQuery)
or doResponse('error',"Couldn't connect to the database");
for($i = 0; $i< mysql_num_rows($userFollowingResult);$i++){
$loopArray = array(followed_id => mysql_result($userFollowingResult,$i,"followed_id"),
followed_name => mysql_result($userFollowingResult,$i,"user_name"));
for($j = 0; $j< mysql_num_rows($myFollowingResult);$j++){
if(mysql_result($userFollowingResult,$i,"followed_id")
==mysql_result($myFollowingResult,$j,"followed_id")) {
$loopArray['is_following'] = 'true';
break;
}
if($j==mysql_num_rows($myFollowingResult)-1){
$loopArray['is_following'] = 'false';
break;
}
}
$resultArray[$i] = $loopArray;
}
echo json_encode($resultArray);
Here is a simplified query:
http://sqlfiddle.com/#!2/6b8d6/3
SELECT
user.user_id,
user.user_name,
he.follower_id AS follower_id,
IF(me.followed_id,1,0) AS metoo
FROM following AS he
INNER JOIN user
ON user.user_id = he.followed_id
LEFT JOIN following AS me
ON me.follower_id = 1
AND me.followed_id = he.followed_id
WHERE he.follower_id = 2