Alternative to "IN" that works like "AND" instead of "OR" - mysql

From my understanding, IN works like this:
$arrayName = array(1, 2, 3);
SELECT *
FROM tableName
WHERE productID IN ($arrayName)
is the equivalent of:
SELECT *
FROM tableName
WHERE productID = 1 OR productID = 2 OR productID = 3
I'm wondering if there's a SQL function that works like IN but uses AND in place of OR to compare to an array. Something that would expand to this:
SELECT *
FROM tableName
WHERE productID = 1 AND productID = 2 AND productID = 3
Not that it's necessary, but for context I'm simply creating a sort list for some search results that are being populated on a PHP page via jQuery. I can do what I need with PHP, I'll simply create the query dynamically depending on what options the user has selected, but I'd rather use an intelligent SQL function if possible.
***EDIT: Thanks everyone for the help. I explained my problem very poorly and you were still able to sort it out, which I appreciate. I found that someone else had asked this question more eloquently and received an answer that I can use:
Is there something in MySQL like IN but which uses AND instead of OR?
I'm trying to figure out how to accept an answer and close this but I'm having a bit of trouble...

You cannot possibly do this,
SELECT *
FROM tableName
WHERE productID = 1 AND productID = 2 AND productID = 3
the condition will always returns false because a row can have only one value on its column, the alternative way to do this is by grouping the result, ex.
SELECT colName
FROM tableName
WHERE productID IN (1,2,3)
GROUP BY colName
HAVING COUNT(DISTINCT colName) = 3
by having a condition HAVING COUNT(DISTINCT colName) = 3, this means that the instance of a record must be equal to the total count of parameters supplied on IN clause.

As written, your query will produce no rows. It is not possible for productID in a row to be equal to both 1 and 2 at the same time.
You are probably looking for a group of rows that contain these three products. Say you want to find orders that have all three products. You can use something like:
select orderid
from orderlines ol
group by orderid
havnig max(case when ol.productid = 1 then 1 else 0 end) > 0 and
max(case when ol.productid = 2 then 1 else 0 end) > 0 and
max(case when ol.productid = 3 then 1 else 0 end) > 0
The GROUP BY with the HAVING clause will find orders where all three products are present.

SELECT orderid
FROM tableName
WHERE productID IN (1, 2, 3)
GROUP BY orderid
HAVING COUNT(DISTINCT productID) = 3 --this number must match the number of unique IDs in the IN clause

Related

Mysql - most efficient way to retrieve data based on multiple selects and wheres

I'm having trouble finding the most efficient way of retrieving various different sumed values from a Mysql table.
Let's say I've got 4 columns - userid, amount, paid, referral.
I'd like to retrieve the following based on a user id:
1 - the sum of amount that is paid (marked as 1)
2 - the sum of amount that is unpaid (marked as 0)
3 - the sum of amount that is paid and referral (marked as 1 on both paid and referral columns)
4 - the sum of amount that unpaid and referral (marked as 0 on paid and 1 on referral columns)
I've tried an embedded select statement like this:
SELECT (
SELECT sum(payout)
FROM table1
WHERE ispaid = 0 and userid = '100'
) AS unpaid
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 1 and userid = '100'
) AS paid,
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 0 and isreferral = 1 and userid = '100'
) AS refpending,
(
SELECT sum(payout)
FROM table1
WHERE ispaid = 1 and isreferral = 1 and userid = '100'
) AS refpaid
This works, but its slow (or at least feels like it could be quicker) on my server, around 1.5 seconds.
I'm sure there is a better way of doing this with a group statement but can't get my head around it!
Any help is much appreciated.
Thanks
You can use conditional expressions inside SUM():
SELECT
SUM(CASE WHEN ispaid=0 THEN payout END) AS unpaid,
SUM(CASE WHEN ispaid=1 THEN payout END) AS paid,
SUM(CASE WHEN ispaid=0 AND isreferral=1 THEN payout END) AS refpending,
SUM(CASE WHEN ispaid=0 AND isreferral=1 THEN payout END) AS refpaid
FROM table1
WHERE userid = '100'
If a given row is not matched by any CASE...WHEN clause, then the value of the expression is NULL, and SUM() ignores NULLs. You could also have an ELSE 0 clause in there if you want to be more explicit, since SUM() will not be increased by a 0.
Also make sure you have an index on userid in this table to select only the rows you need.

How To Find Duplicate, Count and Sum Values from different columns in MySQL?

I have my table
I want to get duplicates from the Name and Status column, count them, and sum values from the Sum column. I want to look like this:
I am new to SQL so that it may be an easy answer, but I can't seem to find a solution.
This is how far I got, but I can't seem to get the count and sum without errors.
SELECT name, COUNT(*) AS recovered
FROM complaints
WHERE status = "Recovered"
GROUP BY name
HAVING COUNT(name) > 0
myQuery
You can do conditional aggregation:
select
name,
sum(status = 'Recovered') recovered,
sum(status = 'Unrecovered') unrecovered,
sum(case when status = 'Recovered' then `sum` end) total_recovered_value,
sum(case when status = 'Unrecovered' then `sum` end) total_unrecovered_value
from mytable
group by name
order by name
Side note: sum is a language keyword, hence not a good choice for a column name.

Count Case Statement - When One Field Greater Than Another

I'm trying to determine how pervasive a particular mistake is in my database. I'm comparing one field against another, and when that field is greater then the other, I want it to count it. I'm also grouping it by a different statement. The purpose of this query is to determine where there are cases in my data base when one price field is larger then another.
The part of the query that is causing problems is "COUNT(CASE when p.IMAP > p.MSRP = 1 ELSE NULL END)" in the select statement. I put two little stars around it, hoping that'd help highlight where it is.
select b.brandName, b.BrandCode, p.ProductVendorStockNumber, **COUNT(Case When p.IMAP > p.MSRP = 1 ELSE NULL END) as 'Count'**
from products p
join brands b on p.brandID = b.brandID
where b.assignedTo = 'Steve' and p.IMAP > p.MSRP and status = 1
GROUP BY b.BrandName
For the count value You could use sum instead of count adding 1 when the condition is true and 0 when false
In sql for aggregated select the select for columns not in aggregated function and not mentioned in group by is deprecated, in the most recent version of mmysql is not allowed and for the older version the result for these values in unpredicatble so you should in group by then column that you have not in aggregation function in select eg:
select b.brandName
, b.BrandCode
, p.ProductVendorStockNumber
,sum(Case When p.IMAP > p.MSRP THEN 1 ELSE 0 END) as my_count
from products p
join brands b on p.brandID = b.brandID
where b.assignedTo = 'Steve' and p.IMAP > p.MSRP and status = 1
GROUP BY b.BrandName, b.BrandCode, p.ProductVendorStockNumber
or filter the result using the rows without aggregation and a join on the right aggregated rows

MySQL count with a range condition

I have a query like this
select newscategory.CategoryName, count(distinct newsmain.id)
from newsmain join newscategory on
newscategory.CategoryName = newsmain.Category
group by CategoryName
and it is returning a correct results, like this:
CategoryName count(distinct newsmain.id)
Acupunctura 1
Neurologie 1
Test Category 2
"newsmain" table has an "AppPublished" datetime field and what I'm trying to do is to add a condition to the count which will do the counting based on if that "AppPublished" is in the range of two datetime variables. For an example, I would need a result like this:
CategoryName count(distinct newsmain.id)
Acupunctura 0
Neurologie 0
Test Category 1
Do I need to make a subquery or is there a way to add some condition to this query?
Because any added conditions in this query are resulting in unwanted filtering of the "CategoryName" column.
You can use a CASE condition like
select newscategory.CategoryName,
count(CASE WHEN AppPublished BETWEEN date1 and date2 THEN distinct newsmain.id END)
from newsmain join newscategory on
newscategory.CategoryName = newsmain.Category
group by CategoryName
(OR) like this
select newscategory.CategoryName,
sum(CASE WHEN AppPublished BETWEEN date1 and date2 THEN 1 ELSE 0 END)
from newsmain join newscategory on
newscategory.CategoryName = newsmain.Category
group by CategoryName

One query for multiple where?

I have a Query which gets the average score from the answers table, And groups it by the category which the question is in.
This query gets the desired result for answers where the coach_id = 0
This is the desired result in which for every coach_id i get another row
Now my question is: Is it possible to also get the same answers from the same table ( so almost the same query ) but where the coach_id = 1 or coach_id = 2.. in the same query?##
This is my query
SELECT
ROUND((SUM(score) / COUNT(vragen.id) * 10),1) as score
FROM antwoorden
JOIN vragen
ON vragen.id = antwoorden.vraag_id
JOIN categorieen
ON categorieen.id = vragen.categorie_id
WHERE antwoorden.werknemer_id = 105 AND antwoorden.coach_id = 0
GROUP BY categorieen.id
Any ideas? Thanks!
What you want is a conditional sum, I think.
Column score_0, that gets the average score for coach_id = 0.
Column score_1, that gets the average score for coach_id = 1.
The count will not work neither, as count ... counts everything! Both coach_id 0 and 1. So you'll have to use a conditional sum there, too.
Besides you'll need the coach_id filter suggested by Neville K.
So:
SELECT
ROUND((
SUM(CASE WHEN antwoorden.coach_id = 0 THEN score ELSE 0 END) /
SUM(CASE WHEN antwoorden.coach_id = 0 THEN 1 ELSE 0 END) * 10
), 1) as score_0,
ROUND((
SUM(CASE WHEN antwoorden.coach_id = 1 THEN score ELSE 0 END) /
SUM(CASE WHEN antwoorden.coach_id = 1 THEN 1 ELSE 0 END) * 10
), 1) as score_1
FROM antwoorden
JOIN vragen
ON vragen.id = antwoorden.vraag_id
JOIN categorieen
ON categorieen.id = vragen.categorie_id
WHERE antwoorden.werknemer_id = 105 AND antwoorden.coach_id IN (0,1)
GROUP BY categorieen.id
I think this is what you meant.
Since you haven't provided your table schemas I would have a hard time writing the query for your actual example. What you want is the SUM(IF(...)) pattern, aggregating on a conditional:
SELECT
foo_id,
SUM(IF(bar_id = 1, baz, 0)) as sum_baz_bar_1,
SUM(IF(bar_id = 2, baz, 0)) as sum_baz_bar_2,
SUM(IF(bar_id = 3, baz, 0)) as sum_baz_bar_3
FROM table
WHERE ...
GROUP BY foo_id
You need to think carefully about your aggregation functions when using this pattern, especially with COUNT or other functions that deal with the presence of a value (such as 0) rather than the value of it.
If you post your table schemas (SHOW CREATE TABLE) or even better set up a sample data set on sqlfiddle.com, I would be happy to help show how to do it with your actual schemas.
Yes.
You can use the in clause
... antwoorden.coach_id in (0, 1, 2)