I am trying to combine multiple selects in one query to use as little data as possible.
I have this sql table (example)
id category status
1 test1 A
2 test2 B
3 test1 A
4 test3 B
5 test1 C
First of all i want to select how many rows there is with the same category.
SELECT category, COUNT(category) FROM test GROUP BY category
Then i would like to count the status in each category. I would do this with this query.
SELECT status, COUNT(status) FROM test WHERE category = 'test1' GROUP BY STATUS
So i want one column with total and then each categorys number of status.
Can i somehow combine these? Is that even possible or do i just have to realize that I have to get the data multiple times to have the right result?
You can try to GROUP BY category and by status and use WITH ROLLUP to get aggregate values:
SELECT category, status, count(*)
FROM test
GROUP BY category, status WITH ROLLUP
The result will look like this:
category | status | count(*)
----------+--------+----------
test1 | A | 2
test1 | C | 1
test1 | NULL | 3
test2 | B | 1
test2 | NULL | 1
test3 | B | 1
test3 | NULL | 1
NULL | NULL | 5
If you ignore the rows containing NULLs, the rest is the regular GROUP BY category, status. There are 2 entries having category = 'test1' AND status = 'A', one entry having category = 'test1' AND status = 'C' and so on.
The third row of the result (category = 'test1', status = NULL, count(*) = 3) summarizes the rows having category = 'test1'. It computes count(*) for all the rows having category = 'test1' no matter what value they have in column status. In a similar way there are computed the summary rows for category = 'test2' and category = 'test3'.
The last row is the summary for the entire table. count(*) = 5 includes all the rows, no matter what value they have in columns category and status.
You can run your second query for all categories at once like this:
mysql> select category, status, count(*) from foo group by category, status;
+----------+--------+----------+
| category | status | count(*) |
+----------+--------+----------+
| test1 | A | 2 |
| test1 | C | 1 |
| test2 | B | 1 |
| test3 | B | 1 |
+----------+--------+----------+
4 rows in set (0.39 sec)
And then you could compute the category-wide count by summing up all its rows. If you really want that too as part of the same query, you could do this:
mysql> select foo.category, status, count(*), cat_count
-> from foo
-> inner join (select category, count(*) cat_count from foo group by category) x
-> on x.category = foo.category
-> group by foo.category, status;
+----------+--------+----------+-----------+
| category | status | count(*) | cat_count |
+----------+--------+----------+-----------+
| test1 | A | 2 | 3 |
| test1 | C | 1 | 3 |
| test2 | B | 1 | 1 |
| test3 | B | 1 | 1 |
+----------+--------+----------+-----------+
4 rows in set (0.00 sec)
Unfortunately MySQL does not support window functions.
One way would be to get your status counts for each category in one query:
SELECT
category,
status,
COUNT(*) AS status_count
FROM
test
GROUP BY
category, status
And then INNER JOIN information about count for categories to it like that:
SELECT
a.*, b.category_count
FROM (
SELECT
category,
status,
COUNT(*) AS status_count
FROM
test
GROUP BY
category, status
) a
INNER JOIN ( SELECT category, COUNT(*) AS category_count FROM test GROUP BY category ) b ON
a.category = b.category
Related
I have a mysql table with 2 columns.
+---------+-----------+
| Barcode | StationID |
+---------+-----------+
| 89411 | 1 |
| 89411 | 2 |
| 89411 | 3 |
| 89412 | 1 |
| 89413 | 1 |
+---------+-----------+
I would like to select all valus from Barcode column which have StationID = 1 and do NOT have a StationID different than 1.
As shown in the picture Barcode 89411 appears three times with different StationID and should be excluded from the result.
Can you help me make a query?
Another approach is to use an EXISTS query:
SELECT t1.*
FROM yourTable t1
WHERE
t1.StationID = 1 AND
NOT EXISTS (SELECT 1 FROM yourTable t2
WHERE t1.Barcode = t2.Barcode AND t2.StationID <> 1);
Demo
Use aggregation function GROUP_CONCAT, and use HAVING clause to filter out those barcodes, which has only one StationID, that is '1':
SELECT barcode, GROUP_CONCAT(DISTINCT StationID) AS stations
FROM table_name
GROUP BY barcode
HAVING stations = '1';
Try this: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=641d334c5f9e57bbdde07e4f24365f88
select barcode from tablename
group by barcode
having sum(case when sanctionid=1 then 0 else 1 end)=0
output:
barcode
89412
89413
I am trying to simplify multiple queries into 1 and for some reason I am having issues. I would like to update a reference count in a table while counting the ref in another table. Currently all I have is the _Doc_ID from the first table. I would like to look up the _FilePath and then count the number of rows that have the same _FilePath. Then Update the Ref_Count by the number found.
table 1
| _Doc_ID | Ref_Count |
| 1 | |
table 2
| ID | _FilePath |
| 1 | 123/123 |
| 2 | 123/123 |
Expected Results Table 1
| _Doc_ID | Ref_Count |
| 1 | 2 |
first query
SELECT _FilePath AS FilePathResult from database.tableName where _Doc_ID = '1'
second
SELECT count(*) AS TotalCount from database.tableName where _FilePath = FilePathResult
Third
Update table1 SET Ref_Count = TotalCount where _Doc_ID = 1
UPDATE with sub-query will do.
Update table1
SET Ref_Count =
(
SELECT count(*) AS TotalCount from database.tableName
where _FilePath = (SELECT _FilePath AS FilePathResult from database.tableName where _Doc_ID = '1')
)
where _Doc_ID = 1
This question is based on: Select row from left join table where multiple conditions are true
I am now trying to select rows from Table 1, which do not have a connection in Table 2 to a certain property ID.
These are the tables:
Table 1
| ID | Name |
| 1 | test |
| 2 | hello |
Table 2
| ID | PropertyID |
| 1 | 3 |
| 1 | 6 |
| 1 | 7 |
| 2 | 6 |
| 2 | 1 |
I am using the following query (which is working with '='):
SELECT tab1ID
FROM table2
WHERE propertyID != 3 OR propertyID = 6
GROUP BY tab1ID
HAVING COUNT(*) = 2;
This query should return ID=2, but it returns zero rows. What I am doing wrong?
Any help is greatly appreciated!
Edit: I had given a MWE but this is my actual query:
SELECT transactionline.total FROM transactionline
LEFT JOIN product_variant ON product_variant.SKU = transactionline.SKU
LEFT JOIN product ON product_variant.productID = product.productID
LEFT JOIN connect_option_product ON connect_option_product.productID = product.productID
LEFT JOIN productattribute_option ON productattribute_option.optionID = connect_option_product.optionID
WHERE productattribute_option.optionID = 4 OR productattribute_option.optionID = 9
GROUP BY transactionline.lineID
HAVING COUNT(*) = 1
AND SUM(productattribute_option.optionID = 4) = 0
AND SUM(productattribute_option.optionID = 9) > 0
A product can have multiple connections to the optionID's. The goal of this query is to select the total amount where some filters are true or false.
Your grouping is correct. But you need to count how many times the value you do not want is in your group. That count must be zero.
SELECT tab1ID
FROM table2
GROUP BY tab1ID
HAVING sum(propertyID = 6) > 0
AND sum(propertyID = 3) = 0
Let's say i've got this database:
book
| idBook | name |
|--------|----------|
| 1 |Book#1 |
category
| idCateg| category |
|--------|----------|
| 1 |Adventures|
| 2 |Science F.|
book_categ
| id | idBook | idCateg | DATA |
|--------|--------|----------|--------|
| 1 | 1 | 1 | (null) |
| 2 | 1 | 2 | (null) |
I'm trying to select only the books which are in category 1 AND category 2
This is what I've got so far:
SELECT book.* FROM book,book_categ
WHERE book_categ.idCateg = 1 AND book_categ.idCateg = 2
Obviously, this giving 0 results becouse each row has only one idCateg it does work width OR but the results are not what I need. I've also tried to use a join, but I just can't get the results I expect.
Here it's the SQLFiddle of my current project, the data at the begining is just a sample.
SQLFiddle
Any help will be really appreciated.
You could double join with a constraint on the category id:
SELECT a.* FROM book AS a
INNER JOIN book_categ AS b ON a.idBook = b.idBook AND b.idCateg = 1
INNER JOIN book_categ AS c ON a.idBook = c.idBook AND c.idCateg = 2
You could use a subquery:
SELECT a.* FROM book AS a
WHERE
(SELECT COUNT(DISTINCT idCateg) FROM book_categ AS b
WHERE b.idBook = a.idBook AND b.idCateg IN (1,2)) = 2
If you are on MySQL as your fiddle implies, you should prefer the join variant, since most joins are much faster in MySQL than subqueries.
edit
This one should also work:
SELECT a.* FROM book a
INNER JOIN book_categ AS b ON a.idBook = b.idCateg
WHERE b.idCateg IN (5, 6)
GROUP BY idBook
HAVING COUNT(DISTINCT b.idCateg) = 2
and should be faster than the two above, although you have to change the last number according to the number of category ids you are requesting.
Firstly, I apologize for the terrible wording, but I'm not sure how to describe what I'm doing...
I have a table of computer types (id, type, name), called com_types
id | type | name
1 | 1 | Dell
2 | 4 | HP
In a second table, I have each individual computer, with a column 'type_id' to denote what type of computer it is, called com_assets
id | type_id | is_assigned
1 | 4 | 0
2 | 1 | 1
I'd like to create a view that shows each computer type, and how many we have on hand and in use, and a total, so the outcome would be
id | type | name | on_hand | in_use | total |
1 | 1 | Dell | 0 | 1 | 1 |
2 | 4 | HP | 1 | 0 | 1 |
As you can see, the on_hand, in_use, and total columns are dependent on the type_id and is_assigned column in the second table.
So far I have tried this...
CREATE VIEW test AS
SELECT id, type, name,
( SELECT COUNT(*) FROM com_assets WHERE type_id = id AND is_assigned = '0' ) as on_hand,
( SELECT COUNT(*) FROM com_assets WHERE type_id = id AND is_assigned = '1' ) as in_use,
SUM( on_hand + in_use ) AS total
FROM com_types
But all this returns is one column with all correct values, except the total equals ALL of the computers in the other table. Will I need a trigger to do this instead?
on_hand is the count of assigned = 0, and in_use is the count of assigned = 1. You can count them together, without the correlated subqueries, like this:
SELECT
com_types.id,
com_types.type,
com_types.name,
COUNT(CASE WHEN com_assets.is_assigned = 0 THEN 1 END) AS on_hand,
COUNT(CASE WHEN com_assets.is_assigned = 1 THEN 1 END) AS in_use,
COUNT(*) AS total
FROM com_types
JOIN com_assets ON com_types.id = com_assets.id
GROUP BY
com_types.id,
com_types.type,
com_types.name