I hope someone can lend an assist and some advise here. I'm trying to get a fairly complex result and not sure if I can do it as one query with subqueries, a union, or simply separate queries to be merged into excel after the fact.
I'm working with a legacy database from my predecessor with the following tables:
Business (columns working with: id, sector, state)
Forms (columns working with: Submitted (Y/N), id, business_id)
Inventory (Columns working with: In_stock (Y/N), id, form_id)
I'm trying to get a final result that looks like this:
| SubmittedForms | Unsubmitted Forms | Sector | State |
|-----------------------------------------------------|
| 10 | 5 | Agr | UT |
| 0 | 7 | Chem | MT |
| 2 | 1 | Bio | OK |
| 13 | 0 | Chem | NM |
The main problem I'm getting is that while submitted forms doesn't need any further arguments and is a simple count, the unsubmitted forms are dependent on the Inventory.in_stock='Y'. Here's my query for the submitted forms:
SELECT COUNT(Forms.id) AS Submitted, Business.sector, Business.state
FROM Forms
JOIN Business ON Forms.business_id=Business.id
WHERE Forms.submitted='Y'
GROUP BY Business.state, Business.sector
Unfortunately, I can't seem to get the unsubmitted forms number to calculate correctly. It just returns the total count of rows where in_stock is Y for that sector.
If it's easier to run a separate query for Submitted and Unsubmitted that's fine for the end result but I need some help getting the correct count of Unsubmitted forms with the in_stock flagged as Y. Also, I attempted to use a COUNT DISTINCT but takes way too long, was still running after 10 minutes. Another complication I can envision in a single query option is the possibility of 0/null values in either Submitted or Unsubmitted forms
Any help is greatly appreciated!
One option:
SELECT COUNT(CASE WHEN Forms.submitted = 'Y' THEN 1 END) SubmittedForms,
COUNT
( CASE WHEN Forms.submitted = 'N'
AND EXISTS ( SELECT 1
FROM Inventory
WHERE form_id = Forms.id
AND in_stock = 'Y'
)
THEN 1
END
) UnsubmittedForms,
Business.sector Sector,
Business.state State
FROM Forms
RIGHT
OUTER
JOIN Business
ON Forms.business_id = Business.id
GROUP
BY Business.sector,
Business.state
;
Another option, which might perform better:
SELECT COUNT(CASE WHEN Forms.submitted = 'Y' THEN 1 END) SubmittedForms,
COUNT(CASE WHEN Forms.submitted = 'N' THEN 1 END) UnsubmittedForms,
Business.sector Sector,
Business.state State
FROM ( SELECT *
FROM Forms
WHERE submitted = 'Y'
OR id IN ( SELECT DISTINCT form_id
FROM Inventory
AND in_stock = 'Y'
)
) Forms
RIGHT
OUTER
JOIN Business
ON Forms.business_id = Business.id
GROUP
BY Business.sector,
Business.state
;
Related
I have a typical user table in addition to the following feature table
features:
-----------------------
| userId | feature |
-----------------------
| 1 | account |
| 1 | hardware |
| 2 | account |
| 3 | account |
| 3 | hardware |
| 3 | extra |
-----------------------
Basically I am trying to get some counts for reporting purposes. In particular, I am trying to find the number of users with accounts and hardware along with the total number of accounts.
I know I can do the following to get the total number of accounts
SELECT
COUNT(DISTINCT userId) as totalAccounts
FROM features
WHERE feature = "account";
I am unsure as to how to get the number of users with both accounts and hardware though. In this example dataset, the number I am looking for is 2. Users 1 and 3 have both accounts and hardware.
I would prefer to do this in a single query. Possibly using CASE (example for totalAccounts below):
SELECT
COUNT(DISTINCT(CASE WHEN feature = "account" THEN userId END)) as totalAccounts,
COUNT( ? ) as accountsWithHardware
FROM features;
These are two queries - one for the all user count, one for the two-features user count - that you can combine with a cross join:
select
count_all_users.cnt as all_user_count,
count_users_having_both.cnt as two_features_user_count
from
(
select count(distinct userid) as cnt
from features
) count_all_users
cross join
(
select count(*) as cnt
from
(
select userid
from features
where feature in ('account', 'hardware')
group by userid
having count(*) = 2
) users_having_both
) count_users_having_both;
UPDATE: With some thinking, there is a much easier way. Group by user and detect whether feature 1 and feature 2 exists. Then count.
select
count(*) as all_user_count,
count(case when has_account = 1 and has_hardware = 1 then 1 end)
as two_features_user_count
from
(
select
userid,
max(case when feature = 'account' then 1 else 0 end) as has_account,
max(case when feature = 'hardware' then 1 else 0 end) as has_hardware
from features
group by userid
) users;
I've written a query that builds a small table of information from a couple of data sources, it uses a self made table to reference the vehicle model for the final group by which is how the data needs to be viewed, however when I group by vehicle it misses out figures in the subquery column from the group by, i.e. if I group by Prefix it shows the correct numbers, grouped by Vehicle hides off some of the data.
The Prefix can relate to a couple of like vehicle models and hence the need to group by vehicle. Can anyone see what I've done wrong easily from the SQL query below please.
SELECT Vehicle, COUNT(`Chassis-No`) AS Stock,
ROUND((100/COUNT(`Chassis-No`)) * SUM(CASE WHEN `Vehicle Age` > '182' THEN 1 ELSE 0 END),1) AS Perc6Months,
ROUND((100/COUNT(`Chassis-No`)) * SUM(CASE WHEN `Vehicle Age` > '365' THEN 1 ELSE 0 END),1) AS Perc12Months,
(SELECT COUNT(VIN_Prefix) FROM Orderdownload
INNER JOIN VehicleMatrix ON (`VIN_Prefix` LIKE 'S%' AND Prefix = LEFT(`VIN_Prefix`,2)) OR (`VIN_Prefix` NOT LIKE 'S%' AND Prefix = LEFT(`VIN_Prefix`,1)) WHERE DealerCode = 'AA12345' AND `VIN_Prefix` = IF(LEFT(`Chassis-No`,1)='S',LEFT(`Chassis-No`,2),LEFT(`Chassis-No`,1))) As Qty
FROM DealerAgedStock
INNER JOIN VehicleMatrix AS VM
ON (`Chassis-No` LIKE 'S%' AND Prefix = LEFT(`Chassis-No`,2)) OR (`Chassis-No` NOT LIKE 'S%' AND Prefix = LEFT(`Chassis-No`,1))
WHERE `DL Dealer Code` = 'AA12345'
GROUP BY Vehicle
Grouped on Vehicle I get the following:
Vehicle | Perc6Months | Perc12Months | Qty
Mondeo | 37.5 | 0 | 2
Grouped on Prefix I get the following:
VIN_Prefix | Perc6Months | Perc12Months | Qty
S1 | 25 | 0 | 2
S2 | 50 | 0 | 2
Ideally it should look this this:
Vehicle | Perc6Months | Perc12Months | Qty
Mondeo | 37.5 | 0 | 4
Where S1 and S2 are relative to the Vehicle Mondeo, thus it gives me the first instance of subquery rather than adding them together.
My question is: why does the Group By not add the figures together properly from the subquery? I need it to add them to have the correct figures...
I have been trying to do this for over 2 hours but simply cannot figure it out.
I have 2 tables - 'patient' with 'PatientNum' column, and 'insurance_cover' with 'insuranceCode', 'patientNum' columns.
I want to show all patients with insurance, with their patient number and the amount of different insurance companies they are covered by(this is the part I've been having trouble with).
This is what I want the output to look like as the explaination may be confusing
Insurance Cover | Patient Number | Number of insurances
-------------------------------------------------------
With Insurance| 1 | 3
With Insurance| 2 | 1
With Insurance| 3 | 1
No Insurance | 4 | N/A
No Insurance | 5 | N/A
Also I realise I need to use UNION, but I haven't been able to get the first part working yet so haven't attempted that yet
Here is my current attempt
SELECT CONCAT('With Insurance ', pat.`PatientNum`)
AS `Insurance cover + Patient Number`,
CONCAT(pat.`PatientFirstname`, ' ', pat.`PatientSurname`)
AS `Patient Name`,
COUNT(`patientNum`) GROUP BY `patientNum`
FROM `patient` AS pat,
`insurance_cover` AS ins
WHERE ins.`PatientNum` = pat.`PatientNum`
AND ins.PatientNum IN (SELECT ins.`PatientNum`
FROM `insurance_cover`)
GROUP BY pat.`PatientNum`;
Any help is appreciated
Table definitions as requested are at http://imgur.com/a/7k22r (I cannot insert pictures with low rep)
You should use a query like:
SELECT patientNum,
number_of_insurances,
(CASE number_of_insurances WHEN 0 THEN 'Not covered' ELSE 'Covered' END)
FROM (
SELECT patient.patientNum,
count(*) as number_of_insurances,
FROM patient
LEFT JOIN insurance_cover ON patient.patientNum = insurance_cover.patientNum
GROUP BY patient.patientNum
) AS S
Edit: According to comments below, you cannot use JOIN. So here is another (less efficient) answer:
SELECT (CASE (SELECT COUNT(*)
FROM insurance_cover AS i1
WHERE i1.patientNum = p.patientNum
)
WHEN 0 THEN 'Not covered'
ELSE 'Covered'
END) AS covered,
p.patientNum,
(SELECT COUNT(*)
FROM insurance_cover AS i2
WHERE i2.patientNum = p.patientNum
) AS number_of_insurances
FROM patient p
Once again i need yours help ;). I have a lot data and mysql request are slower and slower so the need request that i need i want group in one comand.
My example DB structure:
|product|opinion (pos/neg)|reason|
__________________________________
|milk | pos | good |
|milk | pos |fresh |
|chocolate| neg | old |
|milk | neg | from cow|
So i need information about all diffrent product (GROUP BY) count of it, and count of pos opinion for each product. I want output like that:
|product|count|pos count|
_________________________
|milk | 3 | 2 |
|chocolate| 1 | 0 |
I hope that my explain was good enought ;)
Or go to work: I write two commands
SELECT COUNT(*) as pos count FROM table WHERE product = "milk" AND opinion = "pos" GROUP BY `opinion`
And Second one
SELECT product, COUNT(*) FROM table GROUP BY `product`
I don't know how to join this two request, maybe that is impossible? In my real use code i have additional category collumn and i use WHERE in second command too
select product,
count(*) as total_count
sum(
case when opinion='pos' then 1
else 0 end
) as pos_count
from the_table
group by product;
SELECT product,
COUNT(*) TotalCount,
SUM(opinion = 'pos') POSCount
FROM tableName
GROUP BY product
SUM(opinion = 'pos') is MySQL specific syntax that counts the total of result based from the result of boolean arithmethic. If you want it to be more RDBMS friends, use CASE
SUM(CASE WHEN opinion = 'pos' THEN 1 ELSE 0 END)
SQLFiddle Demo
ok this is very simple yet have been searching for 3 hours and still cant get it to work!
the scenario is i have a db with individual costs of 2 business' and i want to sum the cost of each business and present on screen. now i know this is simple enough and easily done with two SELECTS. but i want to do this in one query!
DB
|cost|business|
|100 | 1 |
|200 | 2 |
|200 | 1 |
|300 | 2 |
so from the table above we know that b1 = 300 and b2 = 500! but none of my queries work!
i have tried UNION and CASE but am unfamiliar with them.
my queries:
first try:
$buscost = mysql_query("SELECT FORMAT(sum(`cost`),2) as `b1` FROM `outgoing` WHERE `business`=1
UNION
SELECT FORMAT(sum(`cost`),2) as `b2` FROM `outgoing` WHERE `business`=2")
or die(mysql_error());
$buscost = mysql_fetch_array($busowe);
second try:
$buscost = mysql_query("SELECT
CASE WHEN `business` = 1 THEN FORMAT(sum(`cost`),2) END AS `b1` ,
CASE WHEN `business` = 2 THEN FORMAT(sum(`cost`),2) END AS `b2`
FROM `outgoing` WHERE `active`='yes' ");
$buscost = mysql_fetch_array($buscost);
*cost is set as float(11,2).
im sure im close i just dont know enough to figure it out, have found similar questions on here but none of the answers helped!
oh and if i print_r, the first only fetches the sum of b1, b2 doesnt exist! and
the second array all i get is the result set of the first case and case 2 "b2" is empty,but exists!! i have checked the tables and there is test data in there for both business'.
please help any advice or a solution is greatly appreciated.
edit:forgot to mention all results will also need to be filtered with where active='yes'
Youn need to group by:
SELECT business, FORMAT(sum(`cost`),2) AS cost
FROM outgoing
WHERE active = 'yes'
GROUP BY business
if you want the format:
business | cost
b1 | 300
b2 | 500
or
SELECT
(
SELECT FORMAT(sum(`cost`),2) as `b1`
FROM `outgoing`
WHERE `business`=1 AND active = 'yes'
GROUP BY business
) AS b1,
(
SELECT FORMAT(sum(`cost`),2) as `b1`
FROM `outgoing`
WHERE `business`=2 AND active = 'yes'
GROUP BY business
) AS b2
if you need the format
b1 | b2
300| 500
SELECT business, SUM(cost)
FROM mytable
GROUP BY
business
Try
SELECT business, SUM(cost) AS totalCost FROM myTable GROUP BY business
you can try this:
select
#num1:=(select sum(actor_id) from actor where actor_id%2=0)as number_1,
#num2:=(select sum(actor_id) from actor where actor_id%2!=0)as number_2,
#num1+#num2 as TOTAL;
or if you need active.
select
#num1:=(select sum(actor_id) from actor where actor_id%2=0 and active='yes')as number_1,
#num2:=(select sum(actor_id) from actor where actor_id%2!=0 and active='yes')as number_2,
#num1+#num2 as TOTAL;