Search data in sql on behalf of list of parameters , - sql

Hi All i am unable to create a query in sql i want to get all employee who's contain the product which i passed in parameter
Ex, i if passed product id 11,12 then its should be return only DeliveryBoyId1 and 2 and if passed the product id 11 then its should be return only DeliveryBoyId 1,2,3 and if i passed productid 11,12,16 then its should return 0 record because there is no delivery boy assigned the product id 11,12,16

I don't know what your table is called so I'm calling it dbo.Delivery. Try this out:
;with CTE as (
select distinct DeliveryBoyId --get all the boys who delivered product 11
from dbo.Delivery
where ProductId = 11
union all --combine the above results with the below
select distinct DeliveryBoyId --get all the boys who delivered product 12
from dbo.Delivery
where ProductId = 12
)
select DeliveryBoyId
from CTE
group by DeliveryBoyId
having count(1) = 2 --get all the boys who appear twice in the above table, once for each product
If you want to match additional products, you can add to the CTE section for other product IDs.
If you want a single solution for any number of products, you can use this instead (which may be a little less readable but more concise and easier to maintain):
select DeliveryBoyId
from (
select distinct DeliveryBoyId, ProductId
from dbo.Delivery
where ProductId in (11, 12)
) s
group by DeliveryBoyId
having count(1) = 2 --number matches number of products you need to match

Related

SELECT random 10% of rows for each category on SQL Server

There is a table of products sold.
row_id
customer
product
date_sold
1
customer_1
thingamajig
01.01.2023
2
customer_12
whosi-whatsi
03.01.2023
3
customer_1
watchamacallit
04.01.2023
4
customer_4
whosi-whatsi
06.01.2023
...
...
...
...
There is always one row per one item.
Let's say customer_1 ordered 100 items total. customer_2 ordered 50 items total. customer_3 ordered 17 items total. How do you select random 10% of rows for each customer? The fraction of rows selected should be rounded up (for example 12 rows total results in 2 selected). That means every customer that bought at least one item should appear in the resulting table. In this case the resulting table for customer_1, customer_2 and customer_3 would have 10 + 5 + 2 = 17 rows.
My initial approach would be to create a temp table, calculate desired row counts for each customer and then loop through the temp table and select rows for each customer. Then insert them to another table and select from that one:
drop table if exists #row_counts
select
customer
ceiling(convert(decimal(10, 2), count(product)) / 10) as row_count
into #row_counts
from products_sold
group by customer
-- then use cursor to loop over #row_counts and insert into the final table
-- for randomness an 'order by newid()' will be used
But this just doesn't feel like the right solution...
You need to know total count and a row count of what you want.
Something like this can perhaps be of service:
EDITED due to it not being randomized properly:
select *
from (
select row_number() over(partition by customerid order by newid()) as sortOrder
, COUNT(*) OVER(PARTITION BY customerID) AS cnt
, *
FROM products
) p
-- Now, we want 10% of total count rounded upwards
WHERE sortOrder <= CEILING(cnt * 0.1)

Select ID with specific values in more than one field

I have a table as follows
groupCode
ProductIdentifier
1
dental
1
membership
2
dental
2
vision
2
health
3
dental
3
vision
I need to find out if a specific groupCode have "dental", "vision" and "health" (all three simultaneously)
The expected result is code 2
What I need to identify is if groupCode 2 has the three products (or two, or whatever the user enters). This is part of a huge kitchen sink query I'm building.
I'm doing
SELECT groupCode
FROM dbo.table
WHERE (productIdentifier = N'dental')
AND (productIdentifier = N'vision')
AND (productIdentifier = N'health')
AND (groupCode = 2)
But clearly is wrong because it's not working.
I tried to do something like its described here but it didn't return a result for me:
Select rows with same id but different value in another column
Thanks.
If each of 'dental','vision' and 'health' occur only once per group identifier, you can group by group identifier and filter by the groups having count(*) = 3:
WITH
-- your input ..
indata(groupCode,ProductIdentifier) AS (
SELECT 1,'dental'
UNION ALL SELECT 1,'membership'
UNION ALL SELECT 2,'dental'
UNION ALL SELECT 2,'vision'
UNION ALL SELECT 2,'health'
UNION ALL SELECT 3,'dental'
UNION ALL SELECT 3,'vision'
)
-- real query starts here ...
SELECT
groupcode
FROM indata
WHERE productidentifier IN ('dental','vision','health')
GROUP BY
groupcode
HAVING COUNT(*) = 3;
-- out groupcode
-- out -----------
-- out 2
As per Marcothesane answer, if you know the groupCode (2) and the number of products (vision, dental and health), 3 in this case, and you need to confirm if that code has those three specific products, this will work for you:
SELECT COUNT(groupCode) AS totalRecords
FROM dbo.table
WHERE (groupCode = 2) AND (productIdentifier IN ('dental', 'vision', 'health'))
HAVING (COUNT(groupCode) = 3)
This will return 3 (number of records = number of products).
Its basically's Marcothesane answer in a way you can "copy/paste" to your code by just changing the table name. You should accept Marcothesane answer.

SQL - Count Results of 2 Columns

I have the following table which contains ID's and UserId's.
ID UserID
1111 11
1111 300
1111 51
1122 11
1122 22
1122 3333
1122 45
I'm trying to count the distinct number of 'IDs' so that I get a total, but I also need to get a total of ID's that have also seen the that particular ID as well... To get the ID's, I've had to perform a subquery within another table to get ID's, I then pass this into the main query... Now I just want the results to be displayed as follows.
So I get a Total No for ID and a Total Number for Users ID - Also would like to add another column to get average as well for each ID
TotalID Total_UserID Average
2 7 3.5
If Possible I would also like to get an average as well, but not sure how to calculate that. So I would need to count all the 'UserID's for an ID add them altogether and then find the AVG. (Any Advice on that caluclation would be appreciated.)
Current Query.
SELECT DISTINCT(a.ID)
,COUNT(b.UserID)
FROM a
INNER JOIN b ON someID = someID
WHERE a.ID IN ( SELECT ID FROM c WHERE GROUPID = 9999)
GROUP BY a.ID
Which then Lists all the IDs and COUNT's all the USERID.. I would like a total of both columns. I've tried warpping the query in a
SELECT COUNT(*) FROM (
but this only counts the ID's which is great, but how do I count the USERID column as well
You seem to want this:
SELECT COUNT(DISTINCT a.ID), COUNT(b.UserID),
COUNT(b.UserID) * 1.0 / COUNT(DISTINCT a.ID)
FROM a INNER JOIN
b
ON someID = someID
WHERE a.ID IN ( SELECT ID FROM c WHERE GROUPID = 9999);
Note: DISTINCT is not a function. It applies to the whole row, so it is misleading to put an expression in parentheses after it.
Also, the GROUP BY is unnecessary.
The 1.0 is because SQL Server does integer arithmetic and this is a simple way to convert a number to a decimal form.
You can use
SELECT COUNT(DISTINCT a.ID) ...
to count all distinct values
Read details here
I believe you want this:
select TotalID,
Total_UserID,
sum(Total_UserID+TotalID) as Total,
Total_UserID/TotalID as Average
from (
SELECT (DISTINCT a.ID) as TotalID
,COUNT(b.UserID) as Total_UserID
FROM a
INNER JOIN b ON someID = someID
WHERE a.ID IN ( SELECT ID FROM c WHERE GROUPID = 9999)
) x

Select multiple rows from a table where field is the max date

I have a table called Product. I need to select all product records that have the MAX ManufatureDate.
Here is a sample of the table data:
Id ProductName ManufactureDate
1 Car 01-01-2015
2 Truck 05-01-2015
3 Computer 05-01-2015
4 Phone 02-01-2015
5 Chair 03-01-2015
This is what the result should be since the max date of all the records is 05-01-2015 and these 2 records have this max date:
Id ProductName ManufactureDate
2 Truck 05-01-2015
3 Computer 05-01-2015
The only way I can think of doing this is by first doing a query on the entire table to find out what the max date is and then store it in a variable #MaxManufatureDate. Then do a second query where ManufactureDate=#MaxManufactureDate. Something tells me there is a better way.
There are 1 million+ records in this table:
Here is the way I am currently doing it:
#MaxManufactureDate = select max(ManufactureDate) from Product
select * from Product where ManufactureDate = #MaxManufactureDate
If figure this is a lot better then doing a subselect in a where clause. Or is this the same exact thing as doing a subselect in a where clause? I am not sure if the query gets ran for each row regardless or if sqlserver stored the variable value in memory.
select * from product
where manufactureDate = (select max(manufactureDate) from product)
The inner select-statements selects the maximum date, the outer all products which have the date.
You can use a subQuery
SELECT *
FROM Product
WHERE ManufactureDate = (
SELECT ManufactureDate
FROM Product
ORDER BY ManufactureDate
LIMIT 1
);`
You may need to use ASC or DESC to collect the right order
Try this pattern:
SELECT Id, ProductName, ManufactureDate
FROM (
SELECT Id, ProductName, ManufactureDate, MAX(ManufactureDate)OVER() AS MaxManufactureDate
FROM Product P
) P
WHERE P.MaxManufactureDate = P.ManufactureDate
Essentially, use a window function to get the data you're looking for in the inline view, then use the where clause in the outer query to match them.

SQL script to not allow insert

I have a query that maps all products to some customer levels. In this case levels 0,5,7 and 8
DELETE FROM ProductCustomerLevel
WHERE CustomerLevelID IN (0, 5, 7, 8)
INSERT ProductCustomerLevel
(
ProductID,
CustomerLevelID
)
SELECT ProductID,
CustomerLevel
FROM dbo.Product p
CROSS JOIN (
SELECT 0 AS CustomerLevel UNION ALL
SELECT 5 UNION ALL
SELECT 7 UNION ALL
SELECT 8
)c
The reason that the Delete begins the SQL script is so that any product that may have been deleted or unmapped from the sites is counted for
Basically this maps all products in a database to these customer levels so that they get a discount.
I now need to create a new customer level, example number 9. These will only have 1 or 2 products applied to it.
How can I change the SQL above so that it does not map those products already in Customer Level 9 to levels 0,5,7 and 8
You can just append a WHERE clause to the end that excludes all products that have an existing connection with level 9;
WHERE ProductID NOT IN (
SELECT ProductID FROM ProductCustomerLevel
WHERE CustomerLevelID=9
)
An SQLfiddle to test with.