MySQL JOIN tables with COUNT values - mysql

I have the following tables in my database.I only listed the important columns which can be used for joining.
I need to get the following output
Currently I'm using two seperate queries for each COUNT value
For assigned licenses
select
products.id,products.name,COUNT(assigned_licenses.id)
from
deployment_users
inner join
assigned_licenses
on
deployment_users.id = assigned_licenses.deployment_user_id
inner join
products
on
assigned_licenses.id = products.id
and
deployment_users.customer_id = 10
group by
assigned_licenses.id
;
For total licenses
select
products.id,products.name,COUNT(total_licenses.id)
from
customers
inner join
total_licenses
on
customers.iccode = licenses.iccode
inner join
products
on
total_licenses.id = products.id
and
customers.id = 10
group by
total_licenses.id
;
Since there are more than a 1,000 products that need to be listed,I want to combine them into a single query.How can I do that?

Your specification leaves some room for interpretation (e.g. can a user have assigned licenses without total licenses? if yes my query will fail.) but I would go with this.
SELECT
products.id,
products.name,
Count(Distinct total_licenses.id) As CountTotalLicenses,
Count(Distinct assigned_liceses.deployment_users_id) As CountAssignedLicenses
FROM products
LEFT JOIN total_licenses ON total_licenses.products_id = products.id
LEFT JOIN customers ON customers.iccode = total_licenses.customers_iccode
LEFT JOIN assigned_licenses ON assigned_liceses.total_licenses_id = total_licenses.id
WHERE
customers.id = 10
GROUP BY
products.id,
products.name
For the future it would be awesome if you could paste code as code and not as an image. People cannot simple copy paste snippets of your code and have to type everything again...

Try joining Both of your query
SELECT * FROM (
(First Query) as assigned_licn
INNER JOIN
(Second Query) as total_licn
USING (id)
);

Related

Mysql (doctrine) - count inner join having count > X

I have SQL to count products with specific properties. I am using it in the products filter. SQL is very long, but here is the primary part:
SELECT COUNT(products.id) as products_count, property_items.description, property_items.id as id
FROM property_items
INNER JOIN product_properties ON property_items.id = product_properties.property_item_id
INNER JOIN products ON product_properties.product_id
INNER JOIN product_properties pp ON products.id = pp.product_id AND (pp.property_item_id IN ($ids))
GROUP BY property_items.id
HAVING COUNT(pp.id) >= $countIds
This works perfectly when I have only the one element in $ids, but when i choose one more, the result is bad. It looks like the sql returns count of all products with any property from $ids, but I need to count only products that contains all properties.
First get all available properties. On each property join products that contains this property and go back to all properties of this product to check, if product contains already checked properties too. Or it is bad idea? I need to keep primary table (FROM table) as property_items.
I need to get result in this format:
=============================
id|description|products_count
=============================
1 |lorem ipsum|10
-----------------------------
2 |dolore sit |2
Thanks for any idea.
Try to use SELECT COUNT (DISTINCT products.id) as cnt
You can get the product ids that have all the properties by doing:
SELECT pp.property_id
FROM property_items pi INNER JOIN
product_properties pp
ON pi.id = pp.property_item_id INNER JOIN
products p
ON pp.product_id = p.id
WHERE pp.property_item_id IN ($ids)
GROUP BY pp.property_id
HAVING COUNT(DISTINCT pp.property_item_id) = $countIds -- has all of them
Note that I rationalized the joins. I think your simplification of the query wasn't quite right. I also added table aliases, so the query is easier to write and to read.
If you want the count of such products, use a subquery:
SELECT COUNT(*)
FROM (SELECT pp.property_id
FROM property_items pi INNER JOIN
product_properties pp
ON pi.id = pp.property_item_id INNER JOIN
products p
ON pp.product_id = p.id
WHERE find_in_set(pp.property_item_id, $ids)
GROUP BY pp.property_id
HAVING COUNT(DISTINCT pp.property_item_id) = $countIds -- has all of them
) ;
Your problem is probably because of this line:
WHERE pp.property_item_id IN ($ids)
If you are passing $ids as a comma-separated string, then your query will not work. Note the replacement above.

Using two inner join tables

I have come up with two queries, both use an inner join on two different tables.
Query 1
SELECT PRODUCTS.CODE, PRODUCTS.REFERENCE, PRODUCTS.TAXCAT, PRODUCTS.DISPLAY,PRODUCTS.NAME, PRODUCTS.PRICEBUY, PRODUCTS.PRICESELL, CATEGORIES.NAME AS CATEGORY
FROM PRODUCTS INNER JOIN CATEGORIES ON PRODUCTS.CATEGORY = CATEGORIES.ID;
Query 2
SELECT PRODUCTS.CODE, PRODUCTS.REFERENCE, PRODUCTS.TAXCAT, PRODUCTS.DISPLAY,PRODUCTS.NAME, PRODUCTS.PRICEBUY, PRODUCTS.PRICESELL,STOCKCURRENT.UNITS AS UNIT FROM PRODUCTS INNER JOIN STOCKCURRENT ON STOCKCURRENT.PRODUCT = PRODUCTS.ID;
Both queries run fine on their own, when I try to use both inner joins together I get errors. This is what I came up with on my own. I'm having trouble understanding the syntax to achieve this.
SELECT PRODUCTS.CODE, PRODUCTS.REFERENCE, PRODUCTS.TAXCAT,
PRODUCTS.DISPLAY,PRODUCTS.NAME, PRODUCTS.PRICEBUY,
PRODUCTS.PRICESELL,STOCKCURRENT.UNITS AS UNIT FROM PRODUCTS INNER JOIN
STOCKCURRENT ON STOCKCURRENT.PRODUCT = PRODUCTS.ID, CATEGORIES.NAME AS
CATEGORY FROM PRODUCTS INNER JOIN CATEGORIES ON PRODUCTS.CATEGORY =
CATEGORIES.ID;
Thank you.
Your attempted query has several syntax problems. Assuming you just want to join together the three tables, you may try the following query:
SELECT
p.CODE,
p.REFERENCE,
p.TAXCAT,
p.DISPLAY,
p.NAME,
p.PRICEBUY,
p.PRICESELL,
s.UNITS AS UNIT,
c.NAME AS CATEGORY
FROM PRODUCTS p
INNER JOIN STOCKCURRENT s
ON s.PRODUCT = p.ID
INNER JOIN CATEGORIES c
ON p.CATEGORY = c.ID;
Note that I introduced table aliases here. These aliases can be used elsewhere in the query to avoid having to repeat the entire table name.
By the way, I can also see taking a union of your two original queries. But without expected output, it was not entirely clear what you want.

MySQL SUM() on identical cells in different columns

I have a database on which I run the following query:
SELECT products.name AS 'Product',
products_used.amount * procedures_perf.amount AS 'Total'
FROM products_used
INNER JOIN procedures ON procedures.pr_id = products_used.pr_id
INNER JOIN products ON products.p_id = products_used.p_id
INNER JOIN procedures_perf ON procedures_perf.pr_id = products_used.pr_id
INNER JOIN hospitals ON hospitals.h_id = procedures_perf.h_id
WHERE hospitals.h_id = "20001"
This produces the following excerpt:
Product Total
-----------------
retractor 402
EB 402
EB 0
retractor 105
EB 0
So there are a number of procedures, which all use a specific set of products. I am trying to select the amount of total products used, whereas it is giving me a list of each product used per procedure. The outcome I would want is this:
Product Total
-----------------
retractor 507
EB 402
I have tried to use SUM() on the multiplication, but it keeps grabbing the total of all products. The only solution I could find online is one where the "Product" field would have to be listed in an IF-clause, but I do not want to hardcore the product names in an IF-statement, as it is an ever expanding list. I am probably overlooking something really obvious...
JUST TO BE CLEAR: Group by products.name is not adding up the total values, it just takes the first value it gets. SUM(x * y) suggestion is throwing out an obscenely large number.
You need to use of group by-
SELECT products.name AS 'Product',
SUM(products_used.amount * procedures_perf.amount) AS 'Total'
FROM products_used
INNER JOIN procedures ON procedures.pr_id = products_used.pr_id
INNER JOIN products ON products.p_id = products_used.p_id
INNER JOIN procedures_perf ON procedures_perf.pr_id = products_used.pr_id
INNER JOIN hospitals ON hospitals.h_id = procedures_perf.h_id
WHERE hospitals.h_id = "20001"
GROUP BY products.name;
Use GROUP BY
SELECT product, SUM(total) as total
FROM tablename
GROUP BY product;
After changing your whole query
SELECT products.name AS 'Product',
SUM(products_used.amount * procedures_perf.amount) AS 'Total'
FROM products_used
INNER JOIN procedures ON procedures.pr_id = products_used.pr_id
INNER JOIN products ON products.p_id = products_used.p_id
INNER JOIN procedures_perf ON procedures_perf.pr_id = products_used.pr_id
INNER JOIN hospitals ON hospitals.h_id = procedures_perf.h_id
WHERE hospitals.h_id = "20001"
GROUP BY products.name;

MySQL select count with join

I am trying to get a list of data from multiple tables in a view for analytics - most of the data comes from one table and then I need to get the counts from multiple other tables to show number of logins, number of users and so on.
I am using the below query (simplified to show only some rows and one join):
Select
companies.company_name, companies.last_login, companies.last_ip,
(SELECT COUNT(*) FROM auditing_master GROUP BY company_id) AS audit_count
From
companies
Left Join
auditing_master On auditing_master.company_id = companies.id
Group by
companies.id
When I run this I get an error:
#2014 - Commands out of sync; you can't run this command now
If I run it without the GROUP BY in the SELECT COUNT (*) then it doesn't give any error but it returns a count of all entries in the auditing_master table regardless of which company it refers to.
How can I get a single query to show me the required data from the companies table whilst also showing a total from auditing master (and others) grouped by the company ID?
Edit
Code when using multiple count/joins:
Select
c.company_name, c.last_login, c.last_ip,
COUNT(am.company_id) AS audit_count,
COUNT(u.company_id) AS users,
COUNT(e.company_id) AS employees
From
companies c
Left Join
auditing_master am On am.company_id = c.id
Left Join
users u On u.company_id = c.id
Left Join
employees e On e.company_id = c.id
Group by
c.id
This query locally in PHPMyAdmin on WAMP with only around 10 companies takes 7 seconds to complete and give "meanngless" results that don't correlate to anything.
Thanks
Inner queries in the SELECT clause must return a SINGLE VALUE RESULT.
Something similar to that, should bring what u need.
Select
companies.company_name, companies.last_login, companies.last_ip,
COUNT(*) AS audit_count
From
companies
Left Join
auditing_master On auditing_master.company_id = companies.id
Group by
companies.id
Did you try this? (No need a subquery because no where clause into it, and LEFT JOIN already add auditing_master rows grouped by company_id = companies.id)
Select
companies.company_name, companies.last_login, companies.last_ip,
COUNT(company_id) AS audit_count
From
companies
Left Join
auditing_master On auditing_master.company_id = companies.id
Group by
companies.id
EDIT
Maybe if you add IF statement to avoid COUNT when there is no auditing_master for a given company.
SELECT
companies.company_name, companies.last_login, companies.last_ip,
IFNULL(am.company_id,0,COUNT(am.company_id)) AS audit_count
FROM
companies
INNER JOIN
auditing_master am ON auditing_master.company_id = companies.id
GROUP BY
companies.id
Feel free to put the entire SQL... Because the problem can be somewhere else!

Speed up an SQL query which uses a FullText Join

I have a situation where I need to JOIN and inner query from a products database, grouping items by name and then using the name column to perform the join, thus:
SELECT p.*, p3.variants, sl.id, l.name as locationName FROM products p
LEFT JOIN (SELECT item, count(DISTINCT id) as variants FROM products GROUP BY item) p3
ON p3.item = p.item
LEFT JOIN stockLevels sl ON sl.id=p.id
LEFT JOIN locations l ON l.id=sl.stockLocation AND l.showStock='1'
WHERE p.id='10459' GROUP BY p.id
Having messed around with the order of JOIN and the query itself, I have determined that having this inner table being created first and performing the first required join makes a difference to the speed of the query, but the inner join (SELECT item, count(DISTINCT id) as variants FROM products GROUP BY item) is giving (at present) 7034 rows, which is needless as only about 5 are required.
If I modify the inner join to:
(SELECT item, count(DISTINCT id) as variants
FROM products *WHERE item LIKE '%SOME VALUE%'* GROUP BY item)
This obviously reduces the number of rows returned by that inner join, and it is roughly twice as fast.
But, I can't do this as I don't have a known value to use for the inner where clause.
Is there any way I can bring the results from the outer table into the inner and produce an inner query that references the outer, ie:
SELECT p.*, p3.variants, sl.id, l.name as locationName FROM products p
LEFT JOIN (SELECT item, count(DISTINCT id) as variants
FROM products *WHERE item LIKE p.item * GROUP BY item) p3 << New Where Clause
ON p3.item = p.item
LEFT JOIN stockLevels sl ON sl.id=p.id
LEFT JOIN locations l ON l.id=sl.stockLocation AND l.showStock='1'
WHERE p.id='10459' GROUP BY p.id
I know that what I have written above won't work, and understand why, but is there a way I could achieve something on these lines?
With the number of records in my database at the moment, this actually isn't an issue, the data is returned very quickly, but I can imagine that in time, when the data grows, it could be.
Note, I did look at making a parentId integer column, instead of grouping by the FullText item but there are lots of other issues within my application, and it didn't seem to speed the query up anyway, for the same reasons as listed above, the inner still had to return all rows
Also Note, this is MySQL
If it helps at all here's the output from EXPLAIN
You can put a correlated subquery in the SELECT clause:
SELECT p.*, sl.id, l.name as locationName,
(SELECT COUNT(distinct id)
FROM products p3
WHERE p3.item = p.item) as variants
FROM products p
LEFT JOIN stockLevels sl ON sl.id=p.id
LEFT JOIN locations l ON l.id=sl.stockLocation AND l.showStock='1'
WHERE p.id='10459' GROUP BY p.id
If only 5 are required, just do it the classic way:
SELECT
p.*,
p3.variants,
sl.id,
l.name as locationName,
(SELECT count(DISTINCT id)
FROM products
WHERE item LIKE p.item GROUP BY item) total
FROM products p
LEFT JOIN stockLevels sl
ON sl.id=p.id
LEFT JOIN locations l
ON l.id=sl.stockLocation AND l.showStock='1'
WHERE p.id='10459' GROUP BY p.id
Here you can access the parent table.