Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

select based on calculated value, optimization

i need to select among other fields the age of a customer at the time he/she bought some product of a specific brand etc, WHERE the customer was for example between 30 and 50 years old.i wrote this query (getAge just uses DATEDIFF to return the age in years)

SELECT DISTINCT customers.FirstName, customers.LastName, 
             products.ProductName,
             dbo.getAge(customers.BirthDate,sales.Datekey)
              AS Age_when_buying
FROM sales
 INNER JOIN dates ON sales.Datekey=dates.Datekey
 INNER JOIN customers ON sales.CustomerKey=customers.CustomerKey
 INNER JOIN products ON sales.ProductKey=products.ProductKey
 INNER JOIN stores ON sales.StoreKey=stores.StoreKey

WHERE stores.StoreName = 'DribleCom Europe Online Store' AND
products.BrandName = 'Proseware' AND
dbo.getAge(customers.BirthDate, sales.Datekey) >= 30 AND
dbo.getAge(customers.BirthDate, sales.Datekey) <=50

and it works but i calculate the age three times.I tried to assign age_when_buying to a variable but it didn't work.My next thought was to use cursor but i feel that there is a more simple way i am missing.The question is: which is the appropriate way to solve this or what are my options?

like image 882
Kwnstantinos Papadas Avatar asked Feb 11 '23 08:02

Kwnstantinos Papadas


2 Answers

Assuming that you only have a limited number of filters you'd like to apply, you could use a Common Table Expression to restructure your query.

I personally find it easier to see all the joins and such in one place, while the filters are similarly grouped together at the bottom...

WITH CTE AS(
    select customers.FirstName
         , customers.LastName
         , dbo.getAge(customers.BirthDate,sales.Datekey) AS Age_when_buying
         , sales.StoreName
         , products.BrandName
         , products.ProductName
    from sales
         INNER JOIN customers on sales.CustomerKey=customers.CustomerKey
         INNER JOIN products ON sales.ProductKey = products.ProductKey
         INNER JOIN stores ON sales.StoreKey = stores.StoreKey
)
SELECT DISTINCT FirstName, LastName, ProductName, Age_when_buying
FROM CTE
WHERE StoreName = 'DribleCom Europe Online Store'
  AND BrandName = 'Proseware'
  AND Age_when_buying BETWEEN 30 AND 50
like image 58
chrisb Avatar answered Feb 13 '23 04:02

chrisb


You should use Cross Apply.

SELECT DISTINCT customers.FirstName, customers.LastName, 
             products.ProductName,
             age.age AS Age_when_buying
FROM sales
 INNER JOIN dates ON sales.Datekey=dates.Datekey
 INNER JOIN customers ON sales.CustomerKey=customers.CustomerKey
 INNER JOIN products ON sales.ProductKey=products.ProductKey
 INNER JOIN stores ON sales.StoreKey=stores.StoreKey
CROSS APPLY
(select dbo.getAge(customers.BirthDate, sales.Datekey) as age) age
WHERE stores.StoreName = 'DribleCom Europe Online Store' AND
products.BrandName = 'Proseware' AND
age.age >= 30 AND
age.age <=50
like image 29
PeterRing Avatar answered Feb 13 '23 04:02

PeterRing