Filter with SQL Server by Group ID - sql

I have two tables and I need to filter the data by filter id depends on the relation to to filter group id.
For example I have this two tables:
Table 1:
ItemID
FilterID
3
122
3
123
3
4
17
123
Table 2:
FilterID
FilterGroupID
122
5
123
5
4
1
If I search by filter id = 123 than all item id with this filter need to be returned.
If I search two or more different filter id that have different group id I need to get only the item ids that have all filter id and group id.
Desired output:
first input: 123 -> return item id =3 and item id = 17
second input: 123,4 -> return item id = 3 because filter id 123 belong to group id 5 and filter id 4 belong to group id 1 and item id 3 is the only one that has this two filters.
third input: 122,123 -> return item id =3 and item id = 17 because both filter id belong to same group.
I am getting a little lost with this query and I will be glad to get some help.
I’ll try to simplify it: Let’s say we have group filter of size and group filter of color. If I filter by size S or M than I need to get all items with this sizes. If I want to add color like blue than the answer will cut the result by: item with size S or M and Color blue. So filter from different group may cut some results

It seems that you want to get every ItemID which has at least one matching filter from each FilterGroupID within your filter input. So within each group you have or logic, and between groups you have and logic
If you store your input in a table variable or Table-Valued parameter, then you can just use normal relational division techniques.
This then becomes a question of Relational Division With Remainder, with multiple divisors.
There are many ways to slice this cake. Here is one option
Join the filter input to the groups, to get each filter's group ID
Use a combination of DENSE_RANK and MAX to get the total distinct groups (you can't use COUNT(DISTINCT in a window function so we need to hack it)
You can change this step to use a subquery instead of window functions. It may be faster or slower
Join the main table, and filter out any ItemIDs which do not have their total distinct groups the same as the main total
SELECT
t1.ItemID
FROM (
SELECT *,
TotalGroups = MAX(dr) OVER ()
FROM (
SELECT
fi.FilterID,
t2.FilterGroupID,
dr = DENSE_RANK() OVER (ORDER BY t2.FilterGroupID)
FROM #Filters fi
JOIN Table2 t2 ON t2.FilterID = fI.FilterID
) fi
) fi
JOIN Table1 t1 ON t1.FilterID = fi.FilterID
GROUP BY
t1.ItemID
HAVING COUNT(DISTINCT FilterGroupID) = MAX(fi.TotalGroups);
db<>fiddle

Related

How do I display grouped ID's as a list with their respective values?

How do I not get all the ID's grouped, but instead listed from first to last; with all their respective values in the columns next to them?
Instead of grouping it, it should show ID 1 and its value, ID 2 and its value. EVEN if the values for the ID is the same. I tried removing the GROUP_CONCAT, but then it's only showing one ID per customfield_value?
SELECT GROUP_CONCAT(virtuemart_product_id), customfield_value, COUNT(*) c
FROM jos_virtuemart_product_customfields
WHERE virtuemart_custom_id = 6
GROUP BY customfield_value
HAVING c > 1
It's working currently, but grouping the ID's and spacing them with a comma. Should just display as in a normal table/list format.
Currently it shows like this(as you can see, it's ALL the same ICOS number, but different ID's. I ONLY need to display the values WHERE the ICOS NUMBER is "duplicate"):
ID ICOS Count
1,2,3 775896 3
It should be displaying like this:
ID ICOS Count
1 775896 1
2 775896 1
3 775896 1
All rows where the customfield_value is not unique:
-- Assuming MySQL
SELECT virtuemart_product_id, customfield_value
, COUNT(*) c -- maybe not needed
FROM jos_virtuemart_product_customfields
WHERE virtuemart_custom_id = 6
AND customfield_value IN
( SELECT customfield_value
FROM jos_virtuemart_product_customfields
WHERE virtuemart_custom_id = 6
GROUP BY customfield_value
HAVING COUNT(*) > 1 -- more than one row exists
)
GROUP BY virtuemart_product_id, customfield_value -- maybe not needed
If the virtuemart_product_id is unique you don't need the outer count/group by as it will always be 1.

SQL select count() of multiple values

Not -- I am working in MS Access, so the SQL is limited.
In my table, there are two relevant fields. F1 has a company name, and F2 has one of 8 text values, referred to here as 1-8.
Given a company name, I need to find how many of each particular text value there is.
For example, given the name 'company1,' there may be 50 records with 'company1' in F1. In F2, there may only be text values 1, 3, and 4 for those 50 records.
In a query (or multiple queries), I need to
1) retrieve every records where F1 = 'company1'
2) Find all the distinct values of F2 where F1 = 'company1.' For instance, for this condition, F2 = either 2, 3, 4, or 7
3) Find how many times each distinct value in F2 are repeated. Cont. above example, there may be ten 2s, ten 3s, ten 4s, and twenty 7s.
The process would look like this --
User inputs 'company1.' The query returns
Value | Count
2 | 10
3 | 10
4 | 10
7 | 20
My general idea was to have a query with a subquery to generate a list of every F2 value where F1 = company1, then a second subquery to generate all the distinct values in that list. Then, somehow, I need to search through the first subquery for the number of times each value from the second query is repeated.
Here is some test code. My issue here is that it returns a count of [Significance Level:] in (etc...) because it checks if the value is in that subquery, instead of doing the main query with each result in that subquery.
SELECT count(*)
FROM (
SELECT [Significance Level:]
FROM all_data_tester WHERE
[Manufacturer Audited:] = 'Airbus Space & Defense')
WHERE [Significance Level:] in (
SELECT distinct [Significance Level:]
FROM all_data_tester
WHERE [Manufacturer Audited:] = 'Airbus Space & Defense'
);
Sorry if this is confusing, it is difficult to explain. I can clarify anything
Use a GROUP BY-clause
SELECT [Significance Level:], Count(*) As Cnt
FROM all_data_tester
WHERE [Manufacturer Audited:] = 'Airbus Space & Defense'
GROUP BY [Significance Level:]
ORDER BY [Significance Level:]
This creates one row per significance level with the corresponding count.
You can also get this count per manufacturer with
SELECT [Manufacturer Audited:], [Significance Level:], Count(*) As Cnt
FROM all_data_tester
GROUP BY [Manufacturer Audited:], [Significance Level:]
ORDER BY [Manufacturer Audited:], [Significance Level:]
This creates one row per manufacturer and significance level with the corresponding count.

Get MAX() on repeating IDs

This is how my query results look like currently. How can I get the MAX() value for each unique id ?
IE,
for 5267139 is 8.
for 5267145 is 4
5267136 5
5267137 8
5267137 2
5267139 8
5267139 5
5267139 3
5267141 4
5267141 3
5267145 4
5267145 3
5267146 1
5267147 2
5267152 3
5267153 3
5267155 8
SELECT DISTINCT st.ScoreID, st.ScoreTrackingTypeID
FROM ScoreTrackingType stt
LEFT JOIN ScoreTracking st
ON stt.ScoreTrackingTypeID = st.ScoreTrackingTypeID
ORDER BY st.ScoreID, st.ScoreTrackingTypeID DESC
GROUP BY will partition your table into separate blocks based on the column(s) you specify. You can then apply an aggregate function (MAX in this case) against each of the blocks -- this behavior applies by default with the below syntax:
SELECT First_column, MAX(Second_column) AS Max_second_column
FROM Table
GROUP BY First_column
EDIT: Based on the query above, it looks like you don't really need the ScoreTrackingType table at all, but leaving it in place, you could use:
SELECT st.ScoreID, MAX(st.ScoreTrackingTypeID) AS ScoreTrackingTypeID
FROM ScoreTrackingType stt
LEFT JOIN ScoreTracking st ON stt.ScoreTrackingTypeID = st.ScoreTrackingTypeID
GROUP BY st.ScoreID
ORDER BY st.ScoreID
The GROUP BY will obviate the need for DISTINCT, MAX will give you the value you are looking for, and the ORDER BY will still apply, but since there will only be a single ScoreTrackingTypeID value for each ScoreID you can pull it out of the ordering.

The MIN() Function Ms Access

this is a sample sql query that i created ms access query. i am trying to get only one row the min(DATE). how ever when i run my query i get multiple lines. any hits? thanks
SELECT tblWarehouseItem.whiItemName,
tblWarehouseItem.whiQty,
tblWarehouseItem.whiPrice,
Min(tblWarehouseItem.whiDateIn) AS MinOfwhiDateIn,
tblWarehouseItem.whiExpiryDate,
tblWarehouseItem.whiwrhID
FROM tblWarehouseItem
GROUP BY tblWarehouseItem.whiDateIn,
tblWarehouseItem.whiItemName,
tblWarehouseItem.whiQty,
tblWarehouseItem.whiPrice,
tblWarehouseItem.whiExpiryDate,
tblWarehouseItem.whiwrhID;
If i have my sql code like that is working as it should:
SELECT MIN(tblWarehouseItem.whiDateIn) FROM tblWarehouseItem;
In the first query, you group by a number of columns. That means the minimum value will be calculated for each group, which in turn means you may have multiple rows. On the other hand, the second query will only get the minimum value for the specified column from all rows, so that there is only one row in the result set.
A simple example is shown below to illustrate the above.
Table:
Key Value
1 1
1 2
2 3
2 4
On Group By Key:
GroupKey MinValue
1 = min(1,2) = 1 -> Row 1
2 = min(3,4) = 3 -> Row 2
On Min (Value)
MinValue
=min(1,2,3,4) = 1 -> Row 1
For a table like above, if you want to select all rows and also show the minimum value from whole table rather than per group, you can do something like this:
select key, (select min(value) from table)
from table
SELECT WI.*
FROM tblWarehouseItem AS WI INNER JOIN (SELECT whiimtID, MIN(tblWarehouseItem.whiDateIn) AS whiDateIn
FROM tblWarehouseItem
GROUP BY whiimtID) AS MinWI ON (WI.whiDateIn = MinWI.whiDateIn) AND (WI.whiimtID = MinWI.whiimtID);

How to group by a column

Hi I know how to use the group by clause for sql. I am not sure how to explain this so Ill draw some charts. Here is my original data:
Name Location
----------------------
user1 1
user1 9
user1 3
user2 1
user2 10
user3 97
Here is the output I need
Name Location
----------------------
user1 1
9
3
user2 1
10
user3 97
Is this even possible?
The normal method for this is to handle it in the presentation layer, not the database layer.
Reasons:
The Name field is a property of that data row
If you leave the Name out, how do you know what Location goes with which name?
You are implicitly relying on the order of the data, which in SQL is a very bad practice (since there is no inherent ordering to the returned data)
Any solution will need to involve a cursor or a loop, which is not what SQL is optimized for - it likes working in SETS not on individual rows
Hope this helps
SELECT A.FINAL_NAME, A.LOCATION
FROM (SELECT DISTINCT DECODE((LAG(YT.NAME, 1) OVER(ORDER BY YT.NAME)),
YT.NAME,
NULL,
YT.NAME) AS FINAL_NAME,
YT.NAME,
YT.LOCATION
FROM YOUR_TABLE_7 YT) A
As Jirka correctly pointed out, I was using the Outer select, distinct and raw Name unnecessarily. My mistake was that as I used DISTINCT , I got the resulted sorted like
1 1
2 user2 1
3 user3 97
4 user1 1
5 3
6 9
7 10
I wanted to avoid output like this.
Hence I added the raw id and outer select
However , removing the DISTINCT solves the problem.
Hence only this much is enough
SELECT DECODE((LAG(YT.NAME, 1) OVER(ORDER BY YT.NAME)),
YT.NAME,
NULL,
YT.NAME) AS FINAL_NAME,
YT.LOCATION
FROM SO_BUFFER_TABLE_7 YT
Thanks Jirka
If you're using straight SQL*Plus to make your report (don't laugh, you can do some pretty cool stuff with it), you can do this with the BREAK command:
SQL> break on name
SQL> WITH q AS (
SELECT 'user1' NAME, 1 LOCATION FROM dual
UNION ALL
SELECT 'user1', 9 FROM dual
UNION ALL
SELECT 'user1', 3 FROM dual
UNION ALL
SELECT 'user2', 1 FROM dual
UNION ALL
SELECT 'user2', 10 FROM dual
UNION ALL
SELECT 'user3', 97 FROM dual
)
SELECT NAME,LOCATION
FROM q
ORDER BY name;
NAME LOCATION
----- ----------
user1 1
9
3
user2 1
10
user3 97
6 rows selected.
SQL>
I cannot but agree with the other commenters that this kind of problem does not look like it should ever be solved using SQL, but let us face it anyway.
SELECT
CASE main.name WHERE preceding_id IS NULL THEN main.name ELSE null END,
main.location
FROM mytable main LEFT JOIN mytable preceding
ON main.name = preceding.name AND MIN(preceding.id) < main.id
GROUP BY main.id, main.name, main.location, preceding.name
ORDER BY main.id
The GROUP BY clause is not responsible for the grouping job, at least not directly. In the first approximation, an outer join to the same table (LEFT JOIN below) can be used to determine on which row a particular value occurs for the first time. This is what we are after. This assumes that there are some unique id values that make it possible to arbitrarily order all the records. (The ORDER BY clause does NOT do this; it orders the output, not the input of the whole computation, but it is still necessary to make sure that the output is presented correctly, because the remaining SQL does not imply any particular order of processing.)
As you can see, there is still a GROUP BY clause in the SQL, but with a perhaps unexpected purpose. Its job is to "undo" a side effect of the LEFT JOIN, which is duplication of all main records that have many "preceding" ( = successfully joined) records.
This is quite normal with GROUP BY. The typical effect of a GROUP BY clause is a reduction of the number of records; and impossibility to query or test columns NOT listed in the GROUP BY clause, except through aggregate functions like COUNT, MIN, MAX, or SUM. This is because these columns really represent "groups of values" due to the GROUP BY, not just specific values.
If you are using SQL*Plus, use the BREAK function. In this case, break on NAME.
If you are using another reporting tool, you may be able to compare the "name" field to the previous record and suppress printing when they are equal.
If you use GROUP BY, output rows are sorted according to the GROUP BY columns as if you had an ORDER BY for the same columns. To avoid the overhead of sorting that GROUP BY produces, add ORDER BY NULL:
SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;
Relying on implicit GROUP BY sorting in MySQL 5.6 is deprecated. To achieve a specific sort order of grouped results, it is preferable to use an explicit ORDER BY clause. GROUP BY sorting is a MySQL extension that may change in a future release; for example, to make it possible for the optimizer to order groupings in whatever manner it deems most efficient and to avoid the sorting overhead.
For full information - http://academy.comingweek.com/sql-groupby-clause/
SQL GROUP BY STATEMENT
SQL GROUP BY clause is used in collaboration with the SELECT statement to arrange identical data into groups.
Syntax:
1. SELECT column_nm, aggregate_function(column_nm) FROM table_nm WHERE column_nm operator value GROUP BY column_nm;
Example :
To understand the GROUP BY clauserefer the sample database.Below table showing fields from “order” table:
1. |EMPORD_ID|employee1ID|customerID|shippers_ID|
Below table showing fields from “shipper” table:
1. | shippers_ID| shippers_Name |
Below table showing fields from “table_emp1” table:
1. | employee1ID| first1_nm | last1_nm |
Example :
To find the number of orders sent by each shipper.
1. SELECT shipper.shippers_Name, COUNT (orders.EMPORD_ID) AS No_of_orders FROM orders LEFT JOIN shipper ON orders.shippers_ID = shipper.shippers_ID GROUP BY shippers_Name;
1. | shippers_Name | No_of_orders |
Example :
To use GROUP BY statement on more than one column.
1. SELECT shipper.shippers_Name, table_emp1.last1_nm, COUNT (orders.EMPORD_ID) AS No_of_orders FROM ((orders INNER JOIN shipper ON orders.shippers_ID=shipper.shippers_ID) INNER JOIN table_emp1 ON orders.employee1ID = table_emp1.employee1ID)
2. GROUP BY shippers_Name,last1_nm;
| shippers_Name | last1_nm |No_of_orders |
for more clarification refer my link
http://academy.comingweek.com/sql-groupby-clause/