IF in WHERE mysql query - php

I have this table.
In MySql I want select this user IF key column do not have custom row AND IF key column have custom row -> value column = yes.
This is my query, but it do not work:
where `value` = if(`key` = 'custom', 'yes', '')

you can use the following statement which select any row has key not equal 'custom' or equal 'custom' and value equal 'yes'
Select * from tableName where `key`<> 'custom' or (`key` = 'custom' and `value` = 'yes')

The specification for the query isn't clear, in that it's open to several different interpretations.
I'm thinking the question is about how to return a particular result, not really about using an IF() function in the WHERE clause. (None of the SQL below uses an IF() function in a WHERE clause.)
Here's one possible interpretation of the specification:
By "select this user", we'll take that to mean we want to return a single copy of the user_id column.
By "IF key column do not have custom row", we'll take that to mean that there does not exist such a row for this user_id, then return this user_id. If such a row does exist, then do not return the user.
By "AND IF key column have custom row -> value column = yes.", we'll take that to mean to return this user_id if there is a row for this user_id that matches the condition.
Based on that interpretation, here's an approach to satisfying the specification using conditional aggregation:
SELECT t.user_id
FROM this_table t
GROUP
BY t.user_id
HAVING SUM(1) = SUM(IF(t.key='custom',IF(t.value='yes',1,0),1))
The expression inside the SUM() aggregate gets evaluated for each row. That expression is designed to return either a 1 or a 0, depending on whether the row matches the specified conditions. The SUM() aggregate totals up those 1s and 0s. And then we compare the result to the total number of rows. That tells us if a "matching" row exists or not.
The counts are by user_id, as identified in the GROUP BY clause.
The MySQL IF() function can be replace with a more portable ANSI CASE expression
HAVING SUM(1) = SUM(CASE
WHEN t.key = 'custom'
THEN CASE
WHEN t.value = 'yes'
THEN 1
ELSE 0
END
ELSE 1
END
)
If the intent is to return all of the detail rows for a user, but excluding all user_id that meet the specification, we could use an EXISTS correlated subquery:
SELECT t.user_id
, t.key
, t.value
FROM this_table t
WHERE NOT EXISTS ( SELECT 1
FROM this_table r
WHERE r.user_id = t.user_id
AND r.key = 'custom'
)
OR EXISTS ( SELECT 1
FROM this_table q
WHERE q.user_id = t.user_id
AND q.key = 'custom'
AND q.value = 'yes'
)

Related

Set a flag on a table based on dependent flags in another table with sql

I would like to set a boolean column in one table based on every row from another table.
For example: I have 3 tables; Table B is the N:M relation between table A and C
Table A: ID, flag
Table B: A-ID, C-ID
Table C: ID, flag
I want to set a.flag to false if only 1 c.flag row is false.
I tried with different case statements but I always get errors or something like this because I'm still learning how to use sql correctly
I think you want:
update a
set flag = (case when exists (select 1
from b join
c
on b.a_id = c.a_id
where c.flag = 'false'
)
then 'false' else 'true'
end);
You haven't specified the database, so I have used strings for the values.
If you specifically want exactly one row, then you would use aggregation:
update a
set flag = (case when 1 = (select count(*)
from b join
c
on b.a_id = c.a_id
where c.flag = 'false'
)
then 'false' else 'true'
end);

select not null column from 2 columns when select data from 3 tables

I want choose the data for one column (comment_graduate_id, comment_employer_id) if isn't NULL. One of them will be NULL, and the second will have a value. So I want choose column with value to call its data from its table:
$stmt = $con->prepare("
SELECT
comments.comment_id,
comments.comment_content,
comments.comment_date_and_time,
graduated.graduate_first_name,
employers.employer_name
FROM comments
INNER JOIN graduated ON
comments.comment_graduate_id = graduated.graduate_id
INNER JOIN employers ON
comments.comment_employer_id = employers.employer_id
WHERE
comments.comment_job_offer_id = ?
ORDER BY comments.comment_id DESC");
There are functions available for this, I prefer to use coalesce() as it is not database specific and it can handle more then 2 parameters as well.
coalesce( comment_graduate_id, comment_employer_id )
This will return comment_graduate_id if not null, otherwise it will return comment_employer_id, if that second column is also null then you will get NULL returned.
The MySQL specific function for this is IFNULL() but I urge you to use coalesce instead.

Laravel eloquent omits null values

I'm trying to do a left join using two tables, where I need to get all user id and name in first which satisfies a condition and total number of rows in the second table for each user. If a user doesn't have a row in the second table, it must be null or zero.
This is my eloquent query.
$users->where('users.access_type', '=', 'type1')->orwhere('users.access_type', '=', 'type2')
->leftJoin(DB::raw("(SELECT user_id, COUNT(*) as count FROM table2 WHERE date > '2014-09-17 16:30:04' GROUP BY user_id) temp_table"), function($leftJoin) {
$leftJoin->on('temp_table.user_id', '=', 'users.user_id');
})->select(DB::raw('users.user_id, users.name, temp_table.count as count'))->orderBy('count')->get();
which doesn't returns the user with null count value. instead it returns the user with least count. I printed the query log and copied the raw query for the above query, filled the values and executed. which works perfectly and also returns the user with null entries. No changes made to the query obtained from query log other than adding the values. Copying the raw query below.
select users.user_id, users.name, temp_table.count as count from `users` left join (SELECT user_id, COUNT(*) as count FROM table2 WHERE date > '2014-09-17 16:30:04' GROUP BY user_id) temp_table on `temp_table`.`user_id` = `users`.`user_id` where `users`.`access_type` = 'type1' or `users`.`access_type` = 'type2' order by `count` asc
I have tried changing the column name of the user_id field for both using as user. Also tries replacing null values with zero using IFNULL. But still no go. Please let me know what am I doing wrong.
In your Eloquent query, you need to replace the last function call ...->first() by ...->get() in order to retrieve all the results instead of only the first one.

Which Clause to use instead of IN Clause in MYSQL

My Question is
Which Clause use instead of IN Clause in MYSQL with PHP
Because IN Clause Limit 1024 character.
My Character limit exceed to 1024 character.
SELECT * FROM TblUser
WHERE Status != 'Deleted' AND UserId IN (0,10,11,12,13,14,15,22,45,114,144,155,156,167,211,439,440,441,443,445,450,455,456,457,458,459,1111,1154,1156,1165,1451,1541,11111,11112,11113,11114,11115,11116,11117,11118,11119,11656,15451,16561,17671,18781,33131,33311,33411,54511,111110,111111,111112,111113,111114,111115,111116,111117,111118,111119,111120,111121,111122,111123,111124,111125,111126,111127,111128,111129,111130,111131,111132,111133,111134,111135,111136,111137,111138,111139,111140,111141,111142,111143,111144,111145,111146,111147,111148,111149,111150,111151,111152,111153,111154,111155,111156,111157,111158,111159,111160,111161,111162,111163,111164,111165,111166,111167,111168,111169,111170,111171,111172,111173,111174,111175,111176,111177,111178,111179,111180,111181,111182,111183,111184,111185,111186,111187,111188,111189,111190,111191,111192,111193,111194,111195,111196,111197,111198,111199,1111100,11112101,11112102,11112103,11112104,11112105,11112106,11112107,11112108,11112109,11112110,11112111,11112112,11112113,11112114,11112115,11112116,11112117,11112118,11112119,11112120,11112121,11112122,11112123,11112124,11112125,11112126,11112127,11112128,11112129,11112130,11112131,11112132,11112133,11112134,11112135,11112136,11112137,11112138,11112139,11112140,11112141,11112142,11112143,11112144,11112145,11112146,11112147,11112148,11112149,11112150,11112151,11112152,11112153,11112154,11112155,11112156,11112157,11112158,11112159,11112160,11112161,11112162,11112163,11112164,11112165,11112166,11112167,11112168,11112169,11112170,11112171,11112172,11112173,11112174,11112175,11112176,11112177,11112178,11112179,11112180,11112181,11112182,11112183,11112184,11112185,11112186,11112187,11112188,11112189,11112190,11112191,11112192,11112193,11112194,11112195,11112196,11112197,11112198,11112199,11112200);
Please help Which Clause use instead of IN Clause in MYSQL with PHP?
Is the list of values that are used in the IN statement always the same, or is that list the result of some other query? If the latter is the case, you could use that query as a subquery:
SELECT * FROM tbluser
WHERE status != 'Deleted'
AND userid IN
( SELECT userid FROM sometable WHERE ... )
Yes you are limited within an IN statement, one thing you could do is create a temporary table which stores the values.
CREATE TEMPORARY TABLE IF NOT EXISTS temp AS (SELECT userid FROM tbluser);
In PHP create your INSERT INTO script:
$str = '0,10,11,12,13,14,15,22,45,114,144,155,156,167,211,439,440,441,443,445,450,455,456,457,458,459,1111,1154,1156,1165,1451,1541,11111,11112,11113,11114,11115,11116,11117,11118,11119,11656,15451,16561,17671,18781,33131,33311,33411,54511,111110,111111,111112,111113,111114,111115,111116,111117,111118,111119,111120,111121,111122,111123,111124,111125,111126,111127,111128,111129,111130,111131,111132,111133,111134,111135,111136,111137,111138,111139,111140,111141,111142,111143,111144,111145,111146,111147,111148,111149,111150,111151,111152,111153,111154,111155,111156,111157,111158,111159,111160,111161,111162,111163,111164,111165,111166,111167,111168,111169,111170,111171,111172,111173,111174,111175,111176,111177,111178,111179,111180,111181,111182,111183,111184,111185,111186,111187,111188,111189,111190,111191,111192,111193,111194,111195,111196,111197,111198,111199,1111100,11112101,11112102,11112103,11112104,11112105,11112106,11112107,11112108,11112109,11112110,11112111,11112112,11112113,11112114,11112115,11112116,11112117,11112118,11112119,11112120,11112121,11112122,11112123,11112124,11112125,11112126,11112127,11112128,11112129,11112130,11112131,11112132,11112133,11112134,11112135,11112136,11112137,11112138,11112139,11112140,11112141,11112142,11112143,11112144,11112145,11112146,11112147,11112148,11112149,11112150,11112151,11112152,11112153,11112154,11112155,11112156,11112157,11112158,11112159,11112160,11112161,11112162,11112163,11112164,11112165,11112166,11112167,11112168,11112169,11112170,11112171,11112172,11112173,11112174,11112175,11112176,11112177,11112178,11112179,11112180,11112181,11112182,11112183,11112184,11112185,11112186,11112187,11112188,11112189,11112190,11112191,11112192,11112193,11112194,11112195,11112196,11112197,11112198,11112199,11112200';
$ids = explode(',', $str);
foreach ($ids as $value){
echo 'INSERT INTO temp VALUES(' . $value . '); </br>';
}
But change the echo for the mysqli query.
Then:
SELECT * FROM tbluser u
where status !='Deleted'
And exists(select * from temp u1 where u1.userid = u.userid)
Or you can do an inner join temp u1 on u1.userid = u.userid
#Abid as you mentioned your question in this case #Guss is right.
What i am thinking if values mentioned IN clause comes from GROUP_CONCAT then might be possible duplicate values exist with comma seperated. So to remove duplicacy we can use DISTINCT.
For example :
SELECT GROUP_CONCAT(UserId) FROM sometable
Above query can give duplicate values.
SELECT GROUP_CONCAT(DISTINCT UserId) FROM sometable
SELECT t1.UserRoleId, t1.EntityId, GROUP_CONCAT( DISTINCT t1.PermissionId ) AS Permissions
FROM userpermission t1, bill_companies t2
WHERE t1.Status = 'Active'
AND t2.status = 'Active'
AND UserGroupId
IN ( 84, 85, 86 )
LIMIT 0 , 30
Above query gives you userid's without duplicacy. This can also reduce the size of comma seperated ids.
Hope this will help.
You could create groups using php if there are Ids which follow by increment e. g. 1,2,3 and replace them by a OR (id >= 1 AND id <= 3)
Alternative approach:
Search Max and Min ID in your List and query using an interval (greater than and less than) and use php to do the job.
If you really want to avoid using IN then you could use FIND_IN_SET():-
SELECT * FROM TblUser
WHERE Status != 'Deleted' AND FIND_IN_SET(UserId, '0,10,11,12,13,14,15,22,45,114,144,155,156,167,211,439,440,441,443,445,450,455,456,457,458,459,1111,1154,1156,1165,1451,1541,11111,11112,11113,11114,11115,11116,11117,11118,11119,11656,15451,16561,17671,18781,33131,33311,33411,54511,111110,111111,111112,111113,111114,111115,111116,111117,111118,111119,111120,111121,111122,111123,111124,111125,111126,111127,111128,111129,111130,111131,111132,111133,111134,111135,111136,111137,111138,111139,111140,111141,111142,111143,111144,111145,111146,111147,111148,111149,111150,111151,111152,111153,111154,111155,111156,111157,111158,111159,111160,111161,111162,111163,111164,111165,111166,111167,111168,111169,111170,111171,111172,111173,111174,111175,111176,111177,111178,111179,111180,111181,111182,111183,111184,111185,111186,111187,111188,111189,111190,111191,111192,111193,111194,111195,111196,111197,111198,111199,1111100,11112101,11112102,11112103,11112104,11112105,11112106,11112107,11112108,11112109,11112110,11112111,11112112,11112113,11112114,11112115,11112116,11112117,11112118,11112119,11112120,11112121,11112122,11112123,11112124,11112125,11112126,11112127,11112128,11112129,11112130,11112131,11112132,11112133,11112134,11112135,11112136,11112137,11112138,11112139,11112140,11112141,11112142,11112143,11112144,11112145,11112146,11112147,11112148,11112149,11112150,11112151,11112152,11112153,11112154,11112155,11112156,11112157,11112158,11112159,11112160,11112161,11112162,11112163,11112164,11112165,11112166,11112167,11112168,11112169,11112170,11112171,11112172,11112173,11112174,11112175,11112176,11112177,11112178,11112179,11112180,11112181,11112182,11112183,11112184,11112185,11112186,11112187,11112188,11112189,11112190,11112191,11112192,11112193,11112194,11112195,11112196,11112197,11112198,11112199,11112200')
However the only limit for the number of entries in an IN clause is set by max_allowed_packet (as others have stated) and the same restriction would apply to this.
max_allowed_packet

Mysql Join Two Queries

I have two queries:
SELECT opr, COUNT(*) FROM table WHERE field = 'YES' GROUP BY opr
SELECT opr, MAX(category) FROM table WHERE field = 'NO' GROUP BY opr
So basically in the first query I am getting the number of transactions a user makes.
In the second query I am getting a category that all of those transactions fall under. I don't want to get all categories for each transaction they made, just the Max of the category field so that I have one entry per operator.
Until now, I have been catching both result sets in separate arrays and the looping through both arrays to get the complete opr->picks->category.
This doesn't always work it sometimes associates the wrong category to the wrong operator.
Is there a way to combine these two queries into one, so that I get the operator and picks, then the MAX(category)? The issue is that the conditions for each query are different on the field column.
SELECT opr,
COUNT(CASE WHEN field = 'YES' THEN 1 END) AS number_of_transactions,
MAX(CASE WHEN field = 'NO' THEN category END) AS category
FROM table
GROUP BY opr ;
The above logic can be attained in one query by using CASE
SELECT opr, COUNT(CASE WHEN `field` = 'YES' THEN opr END) as `count`,
MAX(CASE WHEN `field` = 'NO' THEN category END) as `max`
FROM table GROUP BY opr
Just add it in:
SELECT opr,count(*), MAX(category) FROM table WHERE field = 'YES' GROUP BY opr
You might also be able to drop it from 2 queries to 1 with this:
SELECT opr,count(*), MAX(category), field FROM table GROUP BY opr, field
even faster on the processor, use a sum bool:
select
opr,
sum(field='yes') as transactions,
max(if(field='no',category, null)) as category
from table
group by opr

Categories