I have a MySQL query left joining two tables. This is the current query result:
id | login | privacy-weight | requires
--------------------------------------------
0 | user | 1 | NULL
0 | user2 | 1 | NULL
0 | user3 | 1 | privacy-weight
The query itself is not important, as I'd only like to add a WHERE condition to the query as it is now.
I need to fetch only values which (in my own words):
IF (`requires` = 'privacy-weight'), then `privacy-weight` must equal = 0;
That means, I need this condition:
WHERE `privacy-weight` = 0
BUT only if this is true:
requires = 'privacy-weight'
Can this be done?
EDIT
Obviously this is too difficult to understand, therefore, an example output:
privacy-weight | requires
-------------------------
0 | NULL
1 | NULL
0 | privacy-weight
1 | NULL
These would be ignored (not fetched):
privacy-weight | requires
-------------------------
1 | privacy-weight
You could use this simple test:
WHERE (requires = 'privacy-weight' AND privacy-weight = 0) OR requires <> 'privacy-weight' OR requires IS NULL
The first part (requires = 'privacy-weight' AND privacy-weight = 0) prevents the output of:
privacy-weight | requires
-------------------------
1 | privacy-weight
But keeps:
privacy-weight | requires
-------------------------
0 | privacy-weight
While the second part OR requires <> 'privacy-weight' OR requires IS NULL will keep the following ones:
privacy-weight | requires
-------------------------
0 | NULL
1 | NULL
1 | NULL
I think this should work:
SELECT id, login, ( IF(requires='privacy-weight',0,privacy-weight) ) AS privacy-weight, requires
FROM [mytable]
WHERE [mywhereclause]
For more information on how the IF function works in MySQL see the docs at http://dev.mysql.com/doc/refman/5.5/en/if.html
WHERE CASE WHEN requires = 'privacy-weight' THEN 0 ELSE privacy-weight END = 0
simply:
WHERE NOT (requires='privacy-weight' AND privacy-weight<>0)
There is an IF() function in mysql as #philwinkle posted but it changes the values of the columns, it doesn't affect the rows. You want to add this to your WHERE statement.
SELECT id, login, `privacy-weight`, requires FROM yourtable
WHERE `privacy-weight`=0 AND requires='privacy-weight'
Edit I've changed this back to answer the OP's question as written.
You can do if condition in where clause
SELECT *
FROM mytable
WHERE IF(requires = 'privacy-weight',privacy-weight = 0,1);
But you can achieve it without if too as you have mentioned you ONLY need
SELECT *
FROM mytable
WHERE requires = 'privacy-weight'
AND privacy - weight = 0;
Related
I have a record table and its comment table, like:
| commentId | relatedRecordId | isRead |
|-----------+-----------------+--------|
| 1 | 1 | TRUE |
| 2 | 1 | FALSE |
| 3 | 1 | FALSE |
Now I want to select newCommentCount and allCommentCount as a server response to the browser. Is there any way to select these two fields in one SQL?
I've tried this:
SELECT `isRead`, count(*) AS cnt FROM comment WHERE relatedRecordId=1 GROUP BY `isRead`
| isRead | cnt |
| FALSE | 2 |
| TRUE | 1 |
But, I have to use a special data structure to map it and sum the cnt fields in two rows to get allCommentCount by using an upper-layer programming language. I want to know if I could get the following format of data by SQL only and in one step:
| newCommentCount | allCommentCount |
|-----------------+-----------------|
| 2 | 3 |
I don't even know how to describe the question. So I got no any search result in Google and Stackoverflow. (Because of My poor English, maybe)
Use conditional aggregation:
SELECT SUM(NOT isRead) AS newCommentCount, COUNT(*) AS allCommentCount
FROM comment
WHERE relatedRecordId = 1;
if I under stand you want show sum of newComments Count and all comments so you can do it like
SELECT SUM ( CASE WHEN isRead=false THEN 1 ELSE 0 END ) AS newComment,
Count(*) AS AllComments From comments where relatedRecord=1
also you can make store procedure for it.
To place two result sets horizontally, you can as simple as use a subquery for an expression in the SELECT CLAUSE as long as the number of rows from the result sets match:
select (select count(*) from c_table where isread=false and relatedRecordId=1 ) as newCommentCount,
count(*) as allCommentCount
from c_table where relatedRecordId=1;
I am trying to return a friend list for my users and I'm trying to gather the value matching their user_id.
| ID | user1_id | user1_status | user2_id | user2_status |
| 1 | 1 | 0 | 2 | 0 |
| 2 | 4 | 1 | 5 | 1 |
| 3 | 4 | 1 | 6 | 0 |
| 4 | 1 | 0 | 4 | 1 |
Here is the problem I have, the value I'm look for can be in either "user1_id"/"user2_id" and then I need to return the "user_status" ONLY for the other user. n. I made this table really simple. In my version there is a lot more columns I want my server to avoid returning.
Let's say that the client user_id is 4, so I need the select all the row with user1_id/user2_id equal to 4 and return the other person user_status. In the table, the first case of the value equal to 4 is in user1_id, I need that row to return the user2_id and user2_status.
Here is what I have so far, but it doesn't work:
SELECT `id`
CASE
WHEN `user1_id`='4' THEN `user2_id` AND `user2_status`
WHEN `user2_id`='4' THEN `user1_id` AND `user1_status`
ELSE NULL
END
from 'relationship'
where `user1_id`='4' OR `user2_id`='4'
How do I write this query statement?
If you refer to the CASE syntax you will see that it's defined to return a single column and not a tuple. Additionally, in your query you are trying to get either (user2_id, user_status) or NULL. Here you get a mismatch in the number of columns which is not allowed either.
If you really really want to use CASE you could do:
SELECT `id`
CASE
WHEN `user1_id`='4' THEN `user2_id`,
ELSE NULL
END
CASE
WHEN `user2_id`='4' THEN `user1_id`
ELSE NULL
END
CASE
WHEN `user1_id`='4' THEN `user1_status`
ELSE NULL
END
CASE
WHEN `user2_id`='4' THEN `user2_status`
ELSE NULL
END
FROM 'relationship'
where `user1_id`='4' OR `user2_id`='4'
yes, clunky and confusing. Much Simpler if you use UNION.
SELECT id, user2_id AS uid, user2_status as ustatus FROM relationship WHERE user1_id = 4
UNION
SELECT id, user1_id AS uid, user1_status as ustatus FROM relationship WHERE user2_id = 4
I have a table that looks like this.
| path_id | step | point_id | delay_time | stand_time | access |
| 202 | 1 | 111 | 0 | 0 | 7 |
Which lists point_id's in step order.
E.g.: 111 - step 1, 181 - step 2, etc.
I need to write a query that would take point_id, select ALL values which have higher step within ALL path_id's that have a given value and return a grouped set of point_id's.
I am currently using this query
SELECT DISTINCT `pdb`.`point_id` AS `id`
FROM `path_detail` AS `pda` INNER JOIN
`path_detail` AS `pdb` ON pda.path_id = pdb.path_id
AND pda.step < pdb.step
WHERE
(pda.point_id = 111)
GROUP BY `pdb`.`path_id`
Which doesn't seem to work too reliably.
Any suggestions?
Try:
SELECT Distinct `pdb`.`point_id` AS `id`
FROM `path_detail` AS `pda`, `path_detail` AS `pdb`
WHERE
pda.point_id = 111
AND pda.path_id = pdb.path_id
AND pda.step < pdb.step
Order by `pdb`.`point_id` ASC
I have the following tables:
UserPrivileges:
+--------+------+------+------+
| UserID | Col1 | Col2 | Col3 |
+--------+------+------+------+
| 1 | 0 | 1 | 1 |
| 2 | 0 | 0 | 1 |
| 3 | 1 | 0 | 0 |
| 4 | 1 | 1 | 0 |
+--------+------+------+------+
Data:
+--------+------+------+------+
| DataID | Col1 | Col2 | Col3 |
+--------+------+------+------+
| 1 | A | B | C |
| 2 | D | E | F |
| 3 | G | H | I |
| 4 | J | K | L |
+--------+------+------+------+
My question at its simplest form doesn't has anything to do with the Data table but I just explain it anyways so that I might be doing it the wrong way.
How would I select the Column names from UserPrivileges based on the value ? So that I can use the result in another query to select only those columns.
Something along these lines:
SELECT (COLUMNS_NAME_QUERY_FROM_UserPrivileges(UserID='#')) WHERE DataID = '#' FROM Data
Or I don't mind a better way to manage user Privileges for specific columns.
The answer depends upon your requirements for the result. Do you require a result with a consistent set of columns, regardless of user privs? If so, you could set the disallowed values to null (or some other special value) using a IF clause, e.g.,
SELECT IF (p.col1 = 0 THEN NULL ELSE d.col1) AS col1,
IF (p.col2 = 0 THEN NULL ELSE d.col2) AS col2,
IF (p.col3 = 0 THEN NULL ELSE d.col3) AS col3
FROM Data d,
UserPrivileges p
WHERE p.userId = '#'
AND d.DataId = '#'
Of course, the "special value" could be a problem, since you need a value that would never appear in the data. If you needed to know that difference between a null because the real value is null vs. null because it is a prohibited column then you can't use null.
Another approach would have you simple include the privilege indicator for each column appear in the result, and let your business logic use that to determine which values are visible to the user.
A very different approach would have the result set to contain only the allowed columns. In this case you'll need to build your sql statement dynamically. I don't know if you are doing this in a stored procedure or in a host language, but the basic idea is something like this:
string sqlCmd = "SELECT "
+ (SELECT (FIELDS_NAME_QUERY(UserID='#')
FROM USER_PRIVILEGES
WHERE userid='#')
+ FROM data d
execute sqlCmd
"execute" meaning whatever you have available to execute a string as a sql command.
more after clarification by OP:
Ok, you need sql function that returns a string that looks like "colname1, colname2, ...". The following resembles what it would look like in sql server. syntax
create function
FIELDS_NAME_QUERY (#userid int)
begin
select col1, col2, col3... INTO #col1priv, #col2priv, #col3priv FROM userPrivileges WHERE UserId = #UserId
declare #result varhcar(60)
set #result = ''
if (#col1priv = 1) #result = 'col1'
if (#col2priv = 1) #result = #result + ' ,col2'
if (#col3priv = 1) #result = #result + ' ,col3'
return #result
end
have not tried it, but something like this should work
SELECT (SHOW COLUMNS FROM table WHERE expr) FROM data WHERE DataID = '#'
Check this post for details - How can I get column names from a table in Oracle?
Let us know how you solve this...
In a table I have the following value:
ID | Exercise1 | Exercise2 | Exercise3
1 | 0 | 0 | 0
2 | 0 | 0 | 0
When a user completes an exercise, the db switches from '0' to '1'. I'm looking for an sql query that searches by the ID number of the user returns the lowest column name that is set to 0.
EX:
ID | Exercise1 | Exercise2 | Exercise3
1 | 1 | 1 | 0
Here the query would return with exercise3, since exercise1 and exercise2 have previously been updated and completed by the user.
I found
SELECT COLUMN_NAME FROM information_schema.columns
but can't put it together with the sorting I'm looking for, any help would be deeply appreciated.
If you have only a handful of exercises (e.g. < 5), then you can simply hardcode the query with a series of nested IF() statements.
If you have more than that, then you should change your data model so each user/exercise mapping is stored in a separate row.
Something like this?
SELECT CASE
WHEN Exercise1=0 THEN 'Exercise1'
WHEN Exercise2=0 THEN 'Exercise2'
WHEN Exercise3=0 THEN 'Exercise3'
ELSE NULL
END AS Exercise
FROM MyTable
WHERE ID = SomeID
Hmmm... you have problems because your design is wrong. The problem is that your database design was affected by how you imagine the presentation of the table. But the database thinking is different. The database would be normally designed this way:
StudentID | ExcerciseID | Completed
1 | 1 | 1
1 | 2 | 1
1 | 3 | 0
2 | 1 | 0
....
And then you can do:
select StudentID, min(ExcerciseID) as FirstExcerciseNotCompleted
from Excercises
where Completed = 0
to see first incomplete excercise for each student, or if you want set next completed excercise to Student 1, just do:
update Excercises
set Completed = 1
where Student = 1 and ExcerciseID = (select min(ExcerciseID) from Excercises where StudentID = 1 and Completed = 0)