June 29, 2005 at 5:20 am
Hi,
I have a table product_cities that has product_id+city_id as its key.
I need to find all products that are listed within a selected list of cities. The product should be listed in each and every city selected.
Suppose I select Boston, Chicago and Denver, the select should list all products that is listed in each of these cities.
Hope I made myself clear.
And thx for all the help.
Vis.
June 29, 2005 at 5:28 am
So
select product, city
from product_cities
where city = 'boston' or city = 'chicago' or city = 'denver'
is not what you want? (I know you're using IDs, but the theory's the same) Can you give an example of what you'd like the output to look like?
Regards
The absence of evidence is not evidence of absence
- Martin Rees
The absence of consumable DDL, sample data and desired results is, however, evidence of the absence of my response
- Phil Parkin
June 29, 2005 at 5:35 am
If you are trying to determine products that are IN Boston AND IN Chicago AND IN Denver you will need to create three DISTINCT sub-queries
FROM (SELECT Product FROM Product_Cities WHERE City = 'Boston') 1
INNER JOIN (SELECT Product FROM Product_Cities WHERE City = 'Chicago') 2 ON 1.ID = 2.ID
INNER JOIN (SELECT Product FROM Product_Cities WHERE City = 'Denver') 3 ON 1.ID = 3.ID
AFAIK this is the only way to determine that the product is in ALL the cities NOT JUST in ONE city.
Good Hunting!
AJ Ahrens
webmaster@kritter.net
June 29, 2005 at 5:44 am
Actually this is much simpler :
select productid
from dbo.product_cities
where city in ('boston', 'chicago', 'denver')
GROUP by productid
having count(*) = 3 --number of cities in the in clause.
June 29, 2005 at 6:02 am
Hi,
Thx for the tip. Just to complicate it a little further, if each product can have multiple start and end dates in each city and I keyed in the start date to make it product_id+city_id+start_date, how can I modify the above query to still get my answer.
Thx.
Vis.
June 29, 2005 at 6:15 am
never mind, I think if I put a max(start_date) to it, it should do the trick. Thx anyway. U guys are great.
Vis.
June 29, 2005 at 6:28 am
Depends how the EndDate is defined... Assuming that it's defined to null for the active products, then :
Select ...
where DateEnd is null
group by...
if it's set to a time way far in the future then :
where GetDate() between StartDate and EndDate
June 29, 2005 at 6:43 am
Hi,
Ran into a glitch. When I included the start_date, had to include the city_id too and then then count() part is no longer valid. So, I am still searching for the answer. Any help is appreciated.
Thx.
Vis.
June 29, 2005 at 7:07 am
Can you post the query you are using?
This is something you must do with a derived table, then inner join... if I understand what you need correctly.
Could you also post the expected results vs what you are getting now?
June 29, 2005 at 7:34 am
Hi Remi,
Finally got it. I re-wrote to use sub-queries. Here's a sample :
select distinct prod_id
from prod_cities a
where a.city_id in (207,208)
and exists (select city_id from prod_cities
where city_id = 207
and a.prod_id = prod_id)
and exists (select city_id from prod_cities
where city_id = 208
and a.prod_id = prod_id)
Thx for the support. I can sleep tonight.
Vis.
June 29, 2005 at 7:38 am
Same query, usable for any amount of cities :
select prod_id
from dbo.prod_cities
where city_id in (207,208)
GROUP by prod_id
having count(*) = 2 -- number of cities in the in list
But where do you take into consideration the time period?
June 29, 2005 at 1:56 pm
Finally, here's a version where you can search for all occurances, or 1, or any number you want. The list of wanted items is passed as a string so you can use it in a proc .
IF Object_id('fnSplit_Set') > 0
DROP FUNCTION fnSplit_Set
GO
CREATE FUNCTION [dbo].[fnSplit_Set] (@IDS as varchar(8000), @vcDelimiter varchar(3))
RETURNS TABLE
WITH SCHEMABINDING
AS
Return
Select dtSplitted.EachID from (
SELECT SUBSTRING(@vcDelimiter + @IDs + @vcDelimiter, PkNumber + len(@vcDelimiter),
CHARINDEX(@vcDelimiter, @vcDelimiter + @IDs + @vcDelimiter, PkNumber + len(@vcDelimiter)) - PkNumber - len(@vcDelimiter)) as EachID
FROM dbo.Numbers
WHERE SUBSTRING(@vcDelimiter + @IDs + @vcDelimiter, PkNumber, len(@vcDelimiter)) = @vcDelimiter
AND PkNumber 0
GO
IF Object_id('Numbers') IS NULL
BEGIN
--I use this table for many other string operations as well
CREATE TABLE [Numbers] (
[PkNumber] [int] IDENTITY (1, 1) NOT NULL ,
CONSTRAINT [Pk_Number] PRIMARY KEY CLUSTERED
(
[PkNumber]
) ON [PRIMARY]
) ON [PRIMARY]
Declare @i as int
set @i = 0
while @i = @ItemsCount
)
ORDER BYName
SET NOCOUNT OFF
GO
--find all items
Exec dbo.SearchColumns 'name,id', 2-- 4 row(s) affected
Exec dbo.SearchColumns 'name,id,indid', 3-- 1 row(s) affected
Exec dbo.SearchColumns 'id', 1-- 12 row(s) affected
--find at least 2
Exec dbo.SearchColumns 'name,id,indid', 2-- 5 row(s) affected (instead of 1)
--find at least 1
Exec dbo.SearchColumns 'name', 1-- 10 row(s) affected
Exec dbo.SearchColumns 'name,indid', 1-- 11 row(s) affected
GO
DROP PROCEDURE SearchColumns
--DROP FUNCTION fnSplit_Set
GO
June 30, 2005 at 5:10 am
Hi,
Thx for the help again. But, my boss wants a sql solution. And in the previous case, since there are multiple start and end dates and we can't exactly predict how many a city will have, the having count(*) will not work, unless there is someway to ignore the dates and just count the cities. In the solution that I had posted, in fact the IN clause is not required. Just the EXISTS for the occurence of each city will do. The only problem with that is the sql then becomes dynamic depending on the no. of cities in the list. How do we make that solution generic or I need to find another one like the one provided by you (HAVING COUNT() = x).
One fix that I am looking at currently is to generate a sql query on the fly to list DISTINCT products with an EXISTS for each city in the list in a sub-query. May sound crazy but running out of time.
Maybe, I will show the code in your previous mail and try to convince the guys involved.
Once again, call tell u how much I appreciate all the help.
Vis.
June 30, 2005 at 6:48 am
Read my previous post carefully, execute the code one part at the time if you need to. This can handle any number of cities at the same time. You can also decide how many cities it takes to have a hit (if you supply 5 cities in the list, you can ask the server to send any product that is in 3 cities (@ItemsCount)).
This is an ultra fast static sql that you won't be able to beat with your proposed method.
Viewing 14 posts - 1 through 13 (of 13 total)
You must be logged in to reply to this topic. Login to reply