I want to see with a SQL UPDATE query, whether a id was already used. The response should also differentiate between an invalid id and an id that was already used.
My approach with an example:
Storing voters in a SQL database.
Call table Voters with columns vote_id (unique), voted (0 or 1), and already_voted(0 or 1):
Voter x votes for the first time and has valid vote_id: check voted.
x comes in a second time: reject by checking already_voted.
x comes in a third time: voted and already_voted are both checked. No update. But I want 'no update' for the scenario when the vote_id is invalid.
y has no valid vote_id: no update.
I don't understand why voted jumps back to 0 when already_voted is changed from 0 to 1:
UPDATE Voters
SET already_voted = CASE WHEN voted = 1 THEN 1 END,
voted = CASE WHEN voted = 0 THEN 1 END
WHERE vote_id='12345'
I'm also open for a completely different approach. Thanks for your time.
Try this :
UPDATE Voters
SET already_voted = CASE WHEN voted = 1 THEN 1 ELSE already_voted END,
voted = CASE WHEN voted = 0 THEN 1 ELSE voted END
WHERE vote_id='12345
When voted is already 1 and you use your query , the default of the case expression is being used (for voted column), which is NULL if not specified otherwise.
Related
SQL Fiddle here: http://sqlfiddle.com/#!2/a2e41/8
I have a query which does a number of checks: whether column uidto or uidfrom contain a given value. This works fine, but as soon as I want to exclude when columns hidden1 or hidden2 contain a given value the query returns the results anyway. As soon as I take out the first uidto, uidfrom check, it returns nothing, which is expected. Is there any way to do all the checks? Is one being ignored in favor of the other?
Any ideas?
edit:
This still returns despite column hidden1 containing the value to check for:
SELECT m.threadid,
m.uidto,
m.uidfrom,
m.type,
m.hidden1,
m.hidden2
FROM messages m
WHERE m.uidto = 1
OR m.uidfrom = 1
AND m.hidden1 <> 1
AND m.hidden2 <> 1
GROUP BY threadid;
This seems to honor the exclusions, but does not do the check for uidfrom or uidto containing 1
SELECT m.threadid,
m.uidto,
m.uidfrom,
m.type,
m.hidden1,
m.hidden2
FROM messages m
WHERE m.hidden1 <> 1
AND m.hidden2 <> 1
GROUP BY threadid;
EDIT:
There are several threadid's and I pull the messages belonging to each user involved in the thread (there will only ever be two users) by checking if a value matches uidto or uidfrom, then checking if a users id is in hidden1 or hidden2.
the value of the hidden1 and hidden2 columns is the users id who has opted to hide the thread from himself.
If user 1 deletes his thread, we put his user id (1) into the hidden1 column so that he can't see it, but the other user can. if user id 22, who is involved in the thread as well wants to delete the thread, user id 22 would go in to hidden2, now neither of them can see that thread.
Message threads will only ever be seen by the person who sent the messages in it, or the person receiving them. Nobody else will be involved.
Try this query and let me know.
SELECT m.threadid,
m.uidto,
m.uidfrom,
m.type,
m.hidden1,
m.hidden2
FROM messages m
WHERE (m.uidto = 1 OR m.uidfrom = 1)
AND m.hidden1 <> 1 AND m.hidden2 <> 1
GROUP BY threadid;
the parentheses matter... without them, it assumes you meant this:
WHERE m.uidto = 1 OR ( m.uidfrom = 1 AND m.hidden1 <> 1 AND m.hidden2 <> 1 )
And... it's determined by order of precedence for the operators! I was going to update my answer to include info on that but then I found this amazing SO Post that covers it very well: Mysql or/and precedence?
for clarification: http://sqlfiddle.com/#!2/5f989/26/0
select ThreadID,
Type,
UIDto,
Hidden1,
case when UIDTo is null and Hidden1 is not null then concat('UserTo (',Hidden1,') is hidden')
when UIDTo is not null and Hidden1 is null then concat('UserTo (',UIDTo,') is NOT hidden')
else 'UserTo ('+UIDto+') status is unknown' end as UIDTo_Status,
UIDfrom,
Hidden2,
case when UIDFrom is null and Hidden2 is not null then concat('UserTo (',Hidden2,') is hidden')
when UIDFrom is not null and Hidden2 is null then concat('UserTo (',UIDFrom,') is NOT Hidden')
else 'UserTo ('+UIDfrom+') status is unknown' end as UIDfrom_Status
from messages
I'm building a mysql query but I'm stuck... (I'm logging each minute)
I have 3 tables. Logs, log_field, log_value.
logs -> id, create_time
log_value -> id, log_id,log_field_id,value
log_field -> id, name (one on the entries is status and username)
The values for status can be online,offline and idle...
What I would like to see is from my query is:
When in my logs someone changes from status, I want a row with create_time, username, status.
So for a given user, I want my query to skip rows until a new status appears...
And I need to be able to put a time interval in which status changes are ignored.
Can someone please help ?
Although you have nothing to differentiate an actual "User" (such as by user ID) listed in your post, and what happens if you have two "John Smith" names.
First, an introduction to MySQL #variables. You can think of them as an inline program running while the query is processing rows. You create variables, then change them as each row gets processed, IN THE SAME order as the := assignment in the field selection occurs which is critical. I'll cover that shortly.
Fist an initial premise. You have a field value table of all possible fields that can/do get logged. Of which, two of them exist... one is for the user's name, another for the status you are looking a log changed. I don't know what those internal "ID" numbers are, but they would have to be fixed values per your existing table. In my scenario, I am assuming that field ID = 1 is for the User's Name, and field ID 2 = status column... Otherwise, you would need two more joins to get the field table just to confirm which field was the one you wanted. Obviously my "ID" field values will not match your production tables, so please change those accordingly.
Here's the query...
select FinalAlias.*
from (
select
PQ.*,
if( #lastUser = PQ.LogUser, 1, 0 ) as SameUser,
#lastTime := if( #lastUser = PQ.LogUser, #lastTime, #ignoreTime ) as lastChange,
if( PQ.create_time > #lastTime + interval 20 minute, 1, 0 ) as BeyondInterval,
#lastTime := PQ.create_time as chgTime,
#lastUser := PQ.LogUser as chgUser
from
( select
ByStatus.id,
l.create_time,
ByStatus.Value LogStatus,
ByUser.Value LogUser
from
log_value as ByStatus
join logs l
on ByStatus.log_id = l.id
join log_value as ByUser
on ByStatus.log_id = ByUser.log_id
AND ByUser.log_field_id = 1
where
ByStatus.log_field_id = 2
order by
ByUser.Value,
l.create_time ) PQ,
( select #lastUser := '',
#lastTime := now(),
#ignoreTime := now() ) sqlvars
) FinalAlias
where
SameUser = 1
and BeyondInterval = 1
Now, what's going on. The inner-most query (result alias PQ representing "PreQuery") is just asking for all log values where the field_id = 2 (status column) exists. From that log entry, go to the log table for it's creation time... while we're at it, join AGAIN to the log value table on the same log ID, but this time also look for field_id = 1 so we can get the user name.
Once that is done, get the log ID, Creation time, Status Value and Who it was for all pre-sorted on a per-user basis and sequentially time oriented. This is the critical step. The data must be pre-organized by user/time to compare the "last" time for a given user to the "next" time their log status changed.
Now, the MySQL #variables. Join the prequery to another select of #variables which is given an "sqlvars" query alias. This will pre-initialize the variables fo #lastUser, #lastTime and #ignoreTime. Now, look at what I'm doing in the field list via section
if( #lastUser = PQ.LogUser, 1, 0 ) as SameUser,
#lastTime := if( #lastUser = PQ.LogUser, #lastTime, #ignoreTime ) as lastChange,
if( PQ.create_time > #lastTime + interval 20 minute, 1, 0 ) as BeyondInterval,
#lastTime := PQ.create_time as chgTime,
#lastUser := PQ.LogUser as chgUser
This is like doing the following pseudo code in a loop for every record (which is already sequentially ordered by same person and their respective log time
FOR EACH ROW IN RESULT SET
Set a flag "SameUser" = 1 if the value of the #lastUser is the same
as the current person record we are looking at
if the last user is the same as the previous record
use the #lastTime field as the "lastChange" column
else
use the #ignore field as the last change column
Now, build another flag based on the current record create time
and whatever the #lastTime value is based on a 20 minute interval.
set it to 1 if AT LEAST the 20 minute interval has been meet.
Now the key to the cycling the next record.
force the #lastTime = current record create_time
force the #lastUser = current user
END FOR LOOP
So, if you have the following as a result of the prequery... (leaving date portion off)
create status user sameuser lastchange 20minFlag carry to next row compare
07:34 online Bill 0 09:05 0 07:34 Bill
07:52 idle Bill 1 07:34 0 07:52 Bill
08:16 online Bill 1 07:52 1 08:16 Bill
07:44 online Mark 0 09:05 0 07:44 Mark
07:37 idle Monica 0 09:05 0 07:37 Monica
08:03 online Monica 1 07:37 1 08:03 Monica
Notice first record for Bill. The flag same user = 0 since there was nobody before him. The last change was 9:05 (via the NOW() when creating the sqlvars variables), but then look at the "carry to next row compare". This is setting the #lastTime and #lastUser after the current row was done being compared as needed.
Next row for Bill. It sees he is same as last user previous row, so the SameUser flag is set to 1. We now know that we have a good "Last Time" to compare against the current record "Create Time". So, from 7:34 to 7:52 is 18 minutes and LESS than our 20 minute interval so the 20 minute flag is set to 0. Now, we retain the current 7:52 and Bill for third row.
Third row for Bill. Still Same User (flag=1), last change of 7:52 compared to now 8:16 and we have 24 minutes... So the 20 minute flag = 1. Retain 8:16 and Bill for next row.
First row for Mark. Same User = 0 since last user was Bill. Uses same 9:05 ignore time and don't care about 20 min flag, but now save 7:44 and Mark for next row compare.
On to Monica. Different than Mark, so SameUser = 0, etc to finish similar to Bill.
So, now we have all the pieces and rows considered. Now, take all these and wrap them up as the "FinalAlias" of the query and all we do is apply a WHERE clause for "SameUser = 1" AND "20 Minute Flag" has been reached.
You can strip down the final column list as needed, and remove the where clause to look at results, but be sure to add an outer ORDER BY clause for name/create_time to see similar pattern as I have here.
Expertz plz plz HELP :(
i have a relationship table
r_id usera userb active
13 5 1 0
16 1 2 0
now i want to check if some other users are friends with id no 1 and give me other ids except 1
like for this query i expect the ans to be empty because the condition active=1 is not met
if the condition returns true than i would expect the result as 5,2
so i have formed this query
note:user_id keeps on changing depending upon the session
$user_id = 1
SELECT CASE
WHEN `usera`=$user_id
THEN `userb`
ELSE `usera` END
FROM `relationship`
WHERE `usera`=$user_id
OR `userb`=$user_id and `active`='1'
now the problem is even if the conditon is not met(i.e active=1) it still gives me userb
i want the query to return as empty or null
Thanks,
You are missing some parentheses:
SELECT CASE
WHEN `usera`=$user_id
THEN `userb`
ELSE `usera` END
FROM `relationship`
WHERE `usera`=$user_id
OR (`userb`=$user_id and `active`='1')
or even this which is probably what you are looking for:
SELECT CASE
WHEN `usera`=$user_id
THEN `userb`
ELSE `usera` END
FROM `relationship`
WHERE (`usera`=$user_id OR `userb`=$user_id)
and `active`='1'
Your parentheses are wrong:
$user_id = 1
SELECT CASE
WHEN `usera`=$user_id
THEN `userb`
ELSE `usera` END
FROM `relationship`
WHERE (`usera`=$user_id OR `userb`=$user_id) and `active`='1'
You only seem to care about active users, but you were putting the condition only on the second part of the conditional expression.
I am getting this error
Column count doesn't match value count at row 1
I have a 2 case statments in a MySql Stored Procedure, is it possible that MySql thinks there needs to be a column for each case statement in the table?
Right now the tables have 18 columns, and I have a query that accounts for those 18 columns.
The IMAGE_URL column is only 1 column.
, CASE WHEN IM.DIVISION IN ('C4', 'J3') THEN
CONCAT(VAR_STORE_URL,VAR_IMAGE_URL,IM.EDPNO,'.jpg') END AS IMAGE_URL
, CASE WHEN IM.DIVISION = '30' THEN
(Select PM.imgUrl FROM stage_product_data.product_match PM
WHERE PM.itemno = IM.ITEMNO) END AS IMAGE_URL
You're (possibly) unintentionally creating two columns here, when based on name it appears like you only wanted one. (They're both named IMAGE_URL.)
I'd suspect what you wanted was a multiple case:
, CASE WHEN IM.DIVISION IN ('C4', 'J3') THEN
CONCAT(VAR_STORE_URL,VAR_IMAGE_URL,IM.EDPNO,'.jpg')
WHEN IM.DIVISION = '30' THEN
(Select PM.imgUrl FROM stage_product_data.product_match PM
WHERE PM.itemno = IM.ITEMNO)
ELSE "Something default" END AS IMAGE_URL
I have a log table with following schema:
OperatorId - JobId - Status ( Good/Bad/Ugly )
Alex 6 Good
Alex 7 Good
James 6 Bad
Description: Whenever an operator works on a job, an entry is made along with Status. That's it.
Now I need a report like:
OperatorId - Good Count - Bad Count - Ugly Count
Alex 2 0 0
James 0 1 0
select operatorid,
sum(if(status="good",1,0)) as good,
sum(if(status="bad",1,0)) as bad,
sum(if(status="ugly",1,0)) as ugly
from table
group by operatorid
This is called a Pivot Table. It is done by setting a value 1 or 0 for each state and then summing them up:
SELECT
T.OperatorId,
SUM(T.GoodStat) AS Good,
SUM(T.BadStat) AS Bad,
SUM(T.UglyStat) AS Ugly
FROM
(
SELECT
CASE WHEN Status = 'Good' THEN 1 ELSE 0 END AS GoodStat,
CASE WHEN Status = 'Bad' THEN 1 ELSE 0 END AS BadStat,
CASE WHEN Status = 'Ugly' THEN 1 ELSE 0 END AS UglyStat,
OperatorId
FROM logTable T
)
GROUP BY T.OperatorId
If, like me, you prefer, whenever possible, to calculate counts with COUNT rather than with SUM, here's an alternative solution, which uses a method asked about in this thread:
SELECT
operatorid,
COUNT(status = 'good' OR NULL) as good,
COUNT(status = 'bad' OR NULL) as bad,
COUNT(status = 'ugly' OR NULL) as ugly
FROM table
GROUP BY operatorid