MySQL count with a range condition - mysql

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

Related

Add a column from subquery to the SELECT of main query without applying filteres from WHERE in main query

I need a help with following problem:
So I have a table TABLE1 with columns Date, Name, STAT1, STAT2, PROBLEM1
I have a query like this:
SELECT Date, Name, sum(STAT1), sum(STAT2)
FROM TABLE1
WHERE PROBLEM1 <> 0
GROUP BY Date, Name
The result of this query is what I want but I also need to add 2 columns: TOTALCOUNT which is basically the number of rows for each group without applying the filter (PROBLEM1 <> 0 ) and COUNTERRORS which is count for each group where PROBLEM1 = 0.
So to give you further example. For a Date A, and Name B I have 1000 rows. 300 of them have PROBLEM1 = 0.
I run the first query I mentioned above and it calculates my sum(STAT1), sum(STAT2) based on 700 rows because of the filter WHERE PROBLEM1 <> 0. And I need to find a way to add two columns to the result so in the end my table would look like:
DATE NAME sum(STAT1) sum(STAT2) TOTALCOUNT COUNTERRORS
A B 50 3.5 1000 300
Is it possible to do? I was trying using subqueries but without a success.
You can do conditional aggregation :
SELECT Date, Name,
sum(case when PROBLEM1 <> 0 then stat1 else 0 end) as stat1,
sum(case when PROBLEM1 <> 0 then stat2 else 0 end) as stat2,
count(*) as TOTALCOUNT,
sum(PROBLEM1 = 0) as COUNTERRORS
FROM TABLE1
GROUP BY Date, Name;

SELECT query that displays the name of each record once and the count of instances

Is it possible to write a SELECT query that displays the name of each record once and the count of how many instances of that record there are for certain criteria?
For example, If I have a table with the following records:
How can I get the SELECT query to display the following:
You can use conditional aggregation:
select customer,
sum( status = 'Disposed' ) as num_disposed,
sum( status = 'Transported' ) as num_transported
from t
group by customer;
MySQL treats boolean expressions like integers in a numeric context, with 0 for false and 1 for true. So, just adding up the boolean is a simple way to count the number of rows that match the condition.
you can use a group by on case ansum for case
select customer, sum(case when status ='disposed' then 1 else 0 end) count_disposed
sum(case when status ='trasposed' then 1 else 0 end) count_trasposed
from my_table
group by customer

How to use SELECT DISTINCT properly?

I made query like this:
SELECT DISTINCT TahunMasuk (SELECT COUNT(LamaStudi)
FROM studi WHERE LamaStudi < 2) from studi order by TahunMasuk
but, the query is error. What may I do to solve that query so that I can count LamaStudi based by TahunMasuk? The result example is like this
Here is my table
studi
Thanks in advance
This query should return the result you want:
SELECT TahunMasuk,
COUNT(CASE WHEN LamaStudi < 2 THEN 1 END) AS `LamaStudi < 2`,
COUNT(CASE WHEN LamaStudi BETWEEN 2 AND 2.4 THEN 1 END) AS `LamaStudi < 2-2.4`,
COUNT(CASE WHEN LamaStudi > 2.4 THEN 1 END) AS `LamaStudi > 2.4`,
FROM studi
GROUP BY TahunMasuk;
In your sample data, you have some rows where LamaStudi is NULL, but it's not clear how you want to handle that. If you want NULL to be counted as zero, then you need this small modification:
COUNT(CASE WHEN COALESCE(LamaStudi,0) < 2 THEN 1 END) AS `LamaStudi < 2`,
You were using DISTINCT incorrectly. The DISTINCT option applies to all columns in the select-list.
The following rows are all distinct rows:
a b c
a b d
a e d
DISTINCT keeps a row in the result if any column is different from other rows.
If you want to reduce the result set to rows with distinct values in one column, use GROUP BY.
You can use GROUP BY:
SELECT TahunMasuk, COUNT(*)
FROM studi
GROUP BY TahunMasuk

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

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

select case when not working as expected

I'm trying to understand how this works but can't figure it out yet.
I have made this simple uery to test the case-when-then-end clause...
SELECT case when quantity > 3
then count(*) end the_count_a,
case when quantity <= 3
then count(*) end the_count_b
FROM STOCK
my stock table has 30 items with different quantities, only 10 items have quantity over 3 but this is always returning 30.... WHY?
I think it should be returning two columns with values: 10 and 20
Any help will be appreciated!
Thx,
Leo
The value of count(*) means the count of all records (in the current group), regardless of where it is placed. If you want to count records that match a condition, you need to invert your case statement:
select count(case when quantity > 3 then 1 end) the_count_a,
count(case when quantity <= 3 then 1 end) the_count_b
from stock
SELECT
count(case when quantity > 3 then 1 else null end) end the_count_a,
count(case when quantity <= 3 then 1 else null end) end the_count_b
FROM STOCK
The aggregate function COUNT() in absense of a GROUP BY will return all rows in the table which have not been filtered by a WHERE clause. In your case, what you actually need are two subselects or a UNION, depending if you want columns or rows back:
/* Return columns with subselects */
SELECT
(SELECT COUNT(*) FROM STOCK WHERE quantity > 3) AS the_count_a
(SELECT COUNT(*) FROM STOCK WHERE quantity <= 3) AS the_count_b
MySQL is lenient about the presence of a FROM clause, so it can be omitted from the outer query.
/* Return rows instead of columns with UNION */
SELECT
COUNT(*) AS the_count,
'the_count_a'
FROM STOCK WHERE quantity > 3
UNION ALL
SELECT
COUNT(*) AS the_count,
'the_count_b'
FROM STOCK WHERE quantity <= 30