SQL query count customers - mysql

I need count how many suppliers have status "CLOSED" or "READY FOR AUDIT", but in the same time I don't want to count those suppliers that have status "NULL".
supplier
status
JUSTRITE MANUFACTURING COMPANY
CLOSED
JW SPEAKER CORPORATION
CLOSED
KLEIN TOOLS INC
NULL
KLEIN TOOLS INC
CLOSED
KLEVER INNOVATIONS
CLOSED
LA-CO INDUSTRIES INC
CLOSED
As we can see in this example, there are 5 different customers, but the results will be "4" because KLEINT contains "NULL" and it shouldn't be counted in.

Let's say table is defined like the following:
Table name: your_table with two fields
supplier status
---------------- ------
Then you can get the result by aggregation function count.
SELECT
supplier,
SUM(IFNULL((SELECT 1 FROM your_table WHERE a. supplier = supplier LIMIT 1), 0)) AS cnt
FROM your_table a
WHERE `status` IN ('CLOSED', 'READY')
GROUP BY supplier
HAVING cnt > 0
;

I have made a fiddle for you with the solution as an example
https://www.db-fiddle.com/f/rW914i1yUA5GBK2d9j6PGB/0
also the code should look like this
SELECT count(*)
FROM test
WHERE STATUS IS NOT NULL
AND STATUS IN (
'CLOSED'
,'READY FOR AUDIT'
)
this code ignores NULL values, (but they have to be empty values, not someone typing NULL in the fields. that makes a diffrence)

You can:
select all suppliers which have "CLOSED" or "READY FOR AUDIT" status
remove from the selection all those that have a "NULL" status
SELECT COUNT(DISTINCT supplier)
FROM tab
WHERE status IN ('CLOSED', 'READY FOR AUDIT')
AND supplier NOT IN (SELECT supplier FROM tab WHERE status IS NULL)
Check the demo here.

WITH CTE(COMPANY,STATUSS) AS
(
SELECT 'JUSTRITE MANUFACTURING COMPANY', 'CLOSED' UNION ALL
SELECT'JW SPEAKER CORPORATION', 'CLOSED' UNION ALL
SELECT'KLEIN TOOLS INC' , NULL UNION ALL
SELECT'KLEIN TOOLS INC' , 'CLOSED' UNION ALL
SELECT'KLEVER INNOVATIONS', 'CLOSED' UNION ALL
SELECT'LA-CO INDUSTRIES INC' , 'CLOSED'
)
SELECT COUNT(C.COMPANY)
FROM CTE AS C
WHERE C.STATUSS IN('CLOSED','READY FOR AUDIT')
AND NOT EXISTS
(
SELECT 1 FROM CTE AS X WHERE C.COMPANY=X.COMPANY AND X.STATUSS IS NULL
)
CTE is an example of your data. Please replace it with your table name

Related

MySQL: Output ID based on SUM data in one column based attributes in another column

SQL Table:
Customer
Type
Payment
1
Apples
5
1
Apples
5
1
Oranges
1
1
Oranges
2
2
Apples
7
2
Oranges
3
2
Oranges
6
Based on the above, looking to determine which customers have paid more for apples compared to oranges as a sum of all their payments.
In the case of the above table,
Customer 1 - Apples 10 > Oranges 3
Customer 2 - Apples 7 < Oranges 9
Thus the SQL should output Customer 1
I have attempted multiple queries, with the following as the most promising but getting an invalid use of group function error code 1111.
SELECT a.customer
FROM (SELECT customer, SUM(payment) AS orangespaid FROM table
WHERE type ='Oranges'
GROUP BY customer) o
JOIN table AS a ON a.customer = o.customer
WHERE type = 'Apples' and SUM(payment) > orangespaid
GROUP BY customer
ORDER BY customer;
There are a lot of ways to achieve that.
Here's how you do without sub-query:
SELECT Customer,
SUM(CASE WHEN Type='Apples' THEN Payment ELSE 0 END) AS Apples,
SUM(CASE WHEN Type='Oranges' THEN Payment ELSE 0 END) AS Oranges
FROM table1
GROUP BY Customer
HAVING Apples > Oranges;
Or like this:
SELECT Customer,
SUM(IF(Type='Apples',Payment,0)) > SUM(IF(Type='Oranges',Payment,0)) Chk
FROM table1
GROUP BY Customer
HAVING Chk=1
Or a slight modification of the query above, instead of checking the value in SELECT then filter from HAVING, why not just directly do the checking in HAVING:
SELECT Customer
FROM table1
GROUP BY Customer
HAVING SUM(IF(Type='Apples',Payment,0)) > SUM(IF(Type='Oranges',Payment,0)) != 0;
The first query can also be done in similar way.
Demo fiddle
Side note:
As for the difference between using CASE or IF, it's basically operates the same so it's more to individual preference. I mostly opt to use CASE because of readability and easier to edit (not much usage of parentheses/brackets) but using IF almost every time is shorter to write.
Try moving the SUM into a second subquery instead
SELECT a.customer
FROM (SELECT customer, SUM(payment) AS orangespaid FROM table
WHERE type ='Oranges'
GROUP BY customer) o
JOIN (SELECT customer, SUM(payment) AS applespaid FROM table
WHERE type ='Apples'
GROUP BY customer) AS a ON a.customer = o.customer
WHERE applespaid > orangespaid
ORDER BY customer;
You should try with sum(case when) for each type you want, it might not the best solution but it works.
select a.customer
from (select as1.Customer,
sum(case when type = 'Oranges' then payment else 0 end) AS orangespaid,
sum(case when type = 'Apples' then payment else 0 end) AS applespaid
from as1 group by as1.Customer) a
where applespaid > orangespaid
dbfiddle here

MYSQL Select using WHERE, AND, OR

I am trying to get a selection of data out of my database but am having trouble, I'm sure its something simple that I am not seeing but I cant figure it out.
A table, jobs, has 5 fields: job_id, job_status, job_schedulestatus, job_schedulestatus2, job_schedulestatus3. The id is a auto incremented number, the status can have two values Active or Invoiced and the schedule status can each hold a large number of values that are selected from a drop down but in this case I just want to focus on values called FOC, Cancelled and Sample.
What I am trying to do is select all values that are set to active and don't have FOC, Cancelled or Sample set in the schedule status 1-3
Here is my select statement:
SELECT job_id, job_status, job_schedulestatus, job_schedulestatus2, job_schedulestatus3
FROM jobs WHERE job_status='Active'
AND ( job_schedulestatus!='FOC' OR job_schedulestatus!='Cancelled' OR job_schedulestatus!='Sample' )
OR ( job_schedulestatus2!='FOC' OR job_schedulestatus2!='Cancelled' OR job_schedulestatus2!='Sample' )
OR ( job_schedulestatus3!='FOC' OR job_schedulestatus3!='Cancelled' OR job_schedulestatus3!='Sample' )
ORDER BY job_id DESC;
This still shows all fields that have FOC, Cancelled or Sample. Now if I remove the != and replace with just = it will only show those with FOC, Cancelled or Sample which suggests to me that there is an issue using the !=. I tried replcaing with <> but still doesn't work.
If I just test it with one check on the schedule status it works as below:
SELECT job_id, job_status, job_schedulestatus, job_schedulestatus2, job_schedulestatus3
FROM jobs WHERE job_status='Active' AND job_schedulestatus!='Cancelled
ORDER BY job_id DESC;
Any Ideas?
Thanks in advance
This seems easier to process:
SELECT job_id
, job_status
, job_schedulestatus
, job_schedulestatus2
, job_schedulestatus3
FROM jobs
WHERE job_status = 'Active'
AND
( job_schedulestatus NOT IN ('FOC','Cancelled','Sample')
OR job_schedulestatus2 NOT IN ('FOC','Cancelled','Sample')
OR job_schedulestatus3 NOT IN ('FOC','Cancelled','Sample')
)
ORDER
BY job_id DESC;
Note that generally, where you find yourself with enumerated columns (above, say, 2) you can be confident that your schema design is sub-optimal.
SELECT job_id, job_status, job_schedulestatus, job_schedulestatus2, job_schedulestatus3
FROM jobs WHERE job_status='Active'
AND (job_schedulestatus NOT IN ('FOC','Cancelled','Sample')
OR job_schedulestatus2 NOT IN ('FOC','Cancelled','Sample')
OR job_schedulestatus3 NOT IN ('FOC','Cancelled','Sample'))
ORDER BY job_id DESC;

select query with if function with multiple choices

I have a query
SELECT UserName,
IF(status=1, 'open', status) status,
IF(status=2, 'closed', status) status,
c_name
FROM ADMIN a
JOIN admin_course_ ad ON a.adminID=ad.fk_user_id
JOIN admin_courses ac ON ac.c_id=ad.fk_c_id
my requirement is i got status=1,2,3,4 from tables so instead of 1 2 3 4 i want to return open closed pending deferso tried
IF(status=1, 'open', status) status,IF(status=2, 'closed', status) status
but i didn't get expected values.Any help would be appreciated.
You can use CASE statement. For example:
SELECT c_name,
UserName,
(CASE status
WHEN 1 THEN 'open'
WHEN 2 THEN 'closed'
WHEN 3 THEN 'pending'
WHEN 4 THEN 'defer'
ELSE "undefined"
END) AS status_title
FROM admin a
JOIN admin_course_ ad ON a.adminID=ad.fk_user_id
JOIN admin_courses ac ON ac.c_id=ad.fk_c_id
I would suggest to create a status types table with the code, name and a description column. Once you have this you will not need any condition on your query, as youll get name by a inner join between tables.
select a.UserName, ..., s.name
from admin a
inner join statuses s on s.statusCode = a.status
join admin_course_ -- rest of your joins and query
...
You can also achieve what you want with a CASE clause of mysql (look this code example took from mysql documentation https://www.w3schools.com/sql/func_mysql_case.asp):
SELECT OrderID, Quantity,
CASE
WHEN Quantity > 30 THEN "The quantity is greater than 30"
WHEN Quantity = 30 THEN "The quantity is 30"
ELSE "The quantity is something else"
END
FROM OrderDetails;
Hope this helps

SQL limit to 5 records, roll up bogus values and print last

I'm trying to use MySQL to print the top 5 company names and user counts in order of subscribers descending. I also want to roll up bogus company names like 'N/A', '' (blank), 'null' and list them as Unspecified at the bottom of the results.
Here is what it should look like:
Company Subscribers
Microsoft 10
Google 8
Facebook 6
Apple 2
Unspecified 9
You can see 'Unspecified' is at the bottom despite it having 9 people.
Normally I use a case statement to roll up these bogus values, like so:
SELECT
CASE
WHEN sc.company_name not in ('null', 'n/a', '')
THEN company_name
ELSE 'Unspecified'
END as company, count(*) as subscribers
from table
group by company
ORDER BY
CASE WHEN company = 'Unspecified' THEN 1 ELSE 0 END, subscribers DESC, company
However, the above approach doesn't work when limiting to 5 records.
I've also tried using a union like so:
select * from
(SELECT
company_name as company, count(*) as subscribers
from table
where company_name not in ('null', 'n/a', '')
group by company
order by subscribers desc, company asc
limit 4) z
union all
select 'Unspecified' as company, count(*) as subscribers
from table
where company_name in ('null', 'n/a', '')
group by company
But this doesn't work because the Unspecified row is not necessarily always in the top 5.
Is this possible in a single SQL statement? I can't use stored procedures or anything fancy because this is for a Jasper report.
Use your first query, but don't put the check for Unspecified in the ORDER BY, and limit it to the top 5. Then put that into a subquery, and reorder that to put unspecified last.
SELECT *
FROM (SELECT
CASE
WHEN sc.company_name not in ('null', 'n/a', '')
THEN company_name
ELSE 'Unspecified'
END as company, count(*) as count
from table
group by company
ORDER BY count DESC
LIMIT 5) AS x
ORDER BY CASE WHEN company = 'Unspecified' THEN 1 ELSE 0 END, count DESC, company

Select count of customers that purchased at least one from two specific categories in the same month

I'm trying to write a query to count the customers that purchased at least one from order_type=0 and one order_type=1 during the same month in 2014
I have two tables.
The order table that have:
order_id
customer_id
aquisition_date
orders_category table:
order_id
order_type (the type of the orders it may have 0, 1, 2, 3, 5, 8 ...etc )
I tried with this query but it didn't work, I know it's not complete and I missed the month condition!
Select count(user_id) From order
join orders_category
on order.order_id = orders_category.order_id
Where (order_type=0 or order_type=1)
and extract (year from order.aquisition_date)=2014
group by user_id
having count (case when type_id=0 then null else null end) > 0
and count (case when type_id=1 then null else null end) > 0;
I don't know how to find users with at least 1 order from order_type=0 & 1 order of order_type=1, in the same month.
You could use this query, based on what you already had. However, I suggest you change the name of the table order to orders as order is a reserved word:
select count(distinct user_id)
from (
select user_id, month(aquisition_date)
from orders
inner join order_category
on orders.order_id = order_category.order_id
where order_type in (0, 1)
and year(aquisition_date) = 2014
group by user_id, month(aquisition_date)
having count(distinct order_type) = 2
) as base
SQL fiddle
I selected the month also in the sub-select, as it will be interesting to look at the output of that query on its own during your analysis.