Database

Archived Posts from this Category

The Morning Brew #405

Posted by on 05 Aug 2009 | Tagged as: .NET, Database, Development, Links, Morning Brew, SysAdmin

This will be the last of the late editions for a while, my summer break is over and its back to work for me tomorrow so The Morning Brew should be returning to its more usual 8-8:30am (UK) publishing time.

Software

  • Spec# and Boogie Released on CodePlex – Matthew Podwysocki highlights the release of Spec# and Boogie on CodePlex under the Microsoft Research Shared Source License Agreement (MSR-SSLA) and Microsoft Public License (MS-PL) respectivly.

Information

Community

  • Microsoft PDC09 – Microsoft PDC 2009 to be held in LA is now accepting registrations, and until 15th September will be offering a $500 discount

The Morning Brew #153

Posted by on 07 Aug 2008 | Tagged as: .NET, Database, Development, Morning Brew

A longer than average post today due to SQL 2008 finally being RTM’d, although it seems that Visual Studio folks should hold off untill the 11th August when the RTM of Visual Studio 2008 SP1 will be made available.

Software

Information

Community

  • Bad News, Good News – stackoverflow – Stackoverflow, the new community from Jeff Atwood and Joel Spolsky has entered beta, and there is a form you can fill in to get onto the beta linked from this post.

AND/OR Searches for related records

Posted by on 22 Oct 2007 | Tagged as: Database, Development, SQL

A common database problem I have to explain to people is creating search functionality which allows a user to find a master record based on it having some or all of a specified set of related records.  To illustrate this, consider a database which defines products, which can each have 0 or more features from a table of features assigned to them. 

ProductFeatureDiagram

The table Product contains the details of the product (in our case, just a name – its an example after all).  A list of features are supplied in the Feature table, and the relationship between a products and a feature is expressed by a record in the ProdFeatureLink table. 

In this example, we will have 3 products, each with a different combination of the three features:

  • Product 1 has Feature 1
  • Product 2 has features 1 and 2
  • Product 3 has features 1, 2 and 3

So, to summarise the data involved we can issue the following query:

select
    p.product_key, P.ProductName, F.FeatureName
from product p
    inner join prodfeaturelink pfl on p.product_key = pfl.product_fkey
    inner join Feature f on f.feature_key = pfl.feature_fkey

This gives the following results:

ProductFeatureSimpleSelectResult

In our first case we are interested in products which have ‘Feature 1’. To find these we can use the previous query with a filter for the feature required:

select P.* from
product p
    inner join ProdFeatureLink pfl on p.product_key = pfl.product_fkey
    inner join feature f on f.feature_key = pfl.feature_fkey
where
    f.featureNAme = 'Feature1'

This gives the following result set:

ProductFeatureOnlyFeature1

This query correctly returns Products 1,2 and 3.

In the next case, we are interested in products which have any or all of two features (Features 2 and 3). Again, this can be achieved by taking our original query and adding a where clause which filters for either of the features.  This filter can be performed using ‘featureName IN (X,Y)‘ or by ‘FeatureName = X OR FeatureNAme = Y‘.

select distinct p.*
from product p
    inner join prodfeaturelink pfl
        on pfl.product_fkey = p.product_key
    inner join feature f
        on f.feature_key = pfl.feature_fkey
where
    f.featureName in ('Feature2', 'Feature3')

And here is the result set:

ProductFeatureEitherOrBoth

In order that we only get one mention of the product record the query above uses the Distinct clause, otherwise we would get duplication of results.

The final case is to find products that have both Features 2 and 3. This isn’t as simple as it might seem – we can’t just use the AND operator in place of the or, as each individual row of our original query’s results cannot contain two feature values. In order to do this, we need some new tools – specifically Group By, Having and an aggregate function or two. 

Our previous query (Feature 2 AND/OR feature 3) provides the basis – we just need a way of finding only products which have both Feature 2 and 3. We can manage this by requiring that the count of the rows for each product is equal to the number of features we are searching for. 

select p.product_key, p.productName
from product p
    inner join ProdFeatureLink pfl on pfl.product_fkey = p.product_key
    inner join feature f on f.feature_key = pfl.feature_fkey
where featureName in ('Feature2', 'Feature3')
group by p.Product_key, p.ProductName
Having Count(product_key) = 2

giving the result set:

ProductFeatureBoth

The placement of the criteria in this query is important. We must use the where to remove any data we are not interested in – so the WHERE filters our data down to only those products which have either feature 2 and 3. We then use the GROUP BY to gather up each product, and finally the HAVING checks that each product has the required number of features.

We can actually merge both the AND and the OR cases of this query together, as the only difference is that for an AND query we must have as many features against the product as we have specified, where as the OR query must have 1 or more.

declare @type char(3)
Set @type='AND'
--Set @type='OR'
select p.product_key, p.productName
from product p
    inner join ProdFeatureLink pfl on pfl.product_fkey = p.product_key
    inner join feature f on f.feature_key = pfl.feature_fkey
where featureName in ('Feature2', 'Feature3', ..., 'Feature n')
group by p.Product_key, p.ProductName
Having Count(product_key)>= CASE WHEN @type='AND' THEN n ELSE1 END

This query does rely slightly on the structure of the data involved. We rely on the fact that each product may only be assigned one instance of a feature- if a product may be assigned more than one instance of each feature then things do become a bit more difficult – but I’m going to save that for a later date.

UPDATE: Here is a SQL script of the examples used in the article:

AND/OR Searches of related records – SQL Script containing examples in the article

« Previous PageNext Page »