How to avoid coalesce for duplicate tables - sql

I have the following database structure:
tblShelter
ShelterId
PetId
ClientId
ShelterName
Address
tblClient
ClientId
PetId
tblPet
PetId
PetName
So, Pet can belong to a shelter or to a registered shelter client (adopted pet).
So my Shelter table has data as follows:
ShelterId PetId ClientId ShelterName
1 100 NULL Test
1 NULL 101 Test
1 102 NULL Test
So, I need to get all PetNames for each shelter (Direct shelter pets or clients)
Here's my query:
Select Coalesce(p.PetName, pclient.PetName) as PetName
from tblShelter s
Left Join tblPet p
on p.PetId = s.PetId
Left Join (select p2.PetId, p2.PetName
from tblClient c
join tblPet p2
on c.PetId = p2.PetId) pclient
on s.PetId = pclient.PetId
where shelterId=1
Question: Is it possible to optimize this query? Currently, it doesn't look pretty. Please note that database structure is shown for simplicity. Unfortunately, it cannot be modified. Is it possible to get rid of coalesce in a smart way or get rid of sub query?

Yes - change your JOIN order:
Select p.PetName
from tblShelter s
Left Join tblClient c
on s.ClientId = c.ClientId
inner join tblPet p
on p.PetId = s.PetId or
p.PetId = c.PetId
where shelterId=1
JOINs aren't strictly based on joining two tables - the ON clauses can reference any table that has already been joined to form either side of the current join. So here, we allow the join to tblPet to be based on either the direct reference (via s.PetId) or via the optionally joined in tblClient.
Of course, you can further simplify the above query by making a smarter ON condition for the join to tblPet - but the way to do that would be to reintroduce the feature you're seeking to avoid - COALESCE. I've no idea what your reasons are for seeking to avoid that feature though.

Related

How to build a complex sql query?

Database design here
I want to get records from the product_spec_data table that are associated with products whose category_id is 5.
Please help me make a query to the database...
All of the relationship are clearly laid out, a simple join across tables would works.
SELECT psd.*
FROM product_spec_data psd
INNER JOIN product_spec_values psv ON psd.id = psv.product_spec_data_id
INNER JOIN products prod ON psv.product_id = prod.id
INNER JOIN categories cat ON prod.category_id = cat.id
-- with category id = 5
WHERE cat.id = 5;
I am not sure what do you mean by complex query. I guess your question is not complete. I think the query for your question (if it is T-SQL) will be as follows
select d.*
from product_spec_data d
left outer join product_spec_values v on d.id=v.product_spec_data_id
left outer join products p on v.product_id=p.id
where p.category_id=5
(I think in MySQL also above syntax will remain same, you may remove [outer] clause in MySQL)

SQL Query between three tables, get data only from one table

I have these 3 tables:
product table
id
siteId
optionsSet table
id
productId
...
option table
id
optionsSetId
code
...
Question:
How can I make a SQL query to select all from option table by knowing these two: option.code and product.siteId ?
I know how to do a query with JOIN on two tables, but I am struggling with joining these three tables.
Something like
SELECT
*
FROM
option
WHERE
code = #code
AND optionsSetId IN
(SELECT
os.id
FROM
optionsSet os
JOIN product p ON os.productId = p.Id
WHERE
p.siteId = #siteId)
where #code is your code parameter and #siteId is your siteid parameter
to use inner joins you would have to join all 3 tables together and that would like
SELECT
DISTINCT o.*
FROM
option o
JOIN optionsSet os ON o.optionsSetId = os.Id
JOIN product p ON os.productId = p.Id
WHERE
o.code = #code
AND p.siteId = #site
if you notice that requires a DISTINCT to only get the data from option. It may be simpler and easier to understand but not very efficient.
another option that someone will probably say is way more awesome is using EXISTS
SELECT
o.*
FROM
OPTION o
WHERE
o.code = #code
AND EXISTS(
SELECT
1
FROM
optionsSet os
JOIN product p ON os.productId = p.Id
WHERE
o.optionSetId = os.Id
AND p.siteId = #siteId
)
I used EXISTS exclusively for a few years and the started working on databases with tables that had +100million records and IN was faster than EXISTS in some cases and identical in the others. Plus IN is less code.
SELECT * FROM option
LEFT JOIN product
ON option.code = product.siteId (+)
--(+) is a left outter join. This should include all of the values in option.code and all of the values in product that have the same siteId as values in option.
I'm unsure on how you want OptionSet to relate to the other 2 databases though?
if you want to include the third tables result you can just add another join on that table for the condition you want.

I want to retrieve data from 4 tables in SQL Server

I want to retrieve data from 4 tables. Patient table has id as PK which is the foreign key in other three tables ett, phar and ssc. Where a patient lie in only one category. i.e patient id pt1 exists in either of the 3 tables. now I want to retrieve patient info along with its associated category.
My query is:
SELECT *
FROM Patient p
INNER JOIN ETT t
ON p.Patient_ID = t.Patient_ID || INNER JOIN Pharmacological ph
ON p.Patient_ID = ph.Patient_ID
I used OR clause because I want only 1 inner join executing at one time. but its not giving me results, any suggestions??
....Patient table has ID as PK which is the foreign key in other three
tables name: ett, phar and ssc where a patient lie in only one
category. Example, patient id pt1 exists in either of the 3 tables.
Based on your statement, you can join all the tables in table Patient using LEFT JOIN since a record can only exist on one table. The query below uses COALESCE which returns the first non-null value with int the list.
The only thing you need is to manually specify the column names that you want to be shown on the list as shown below.
SELECT a.*,
COALESCE(t.colA, p.ColA, s.ColA) ColA,
COALESCE(t.colB, p.ColB, s.ColB) ColB,
COALESCE(t.colN, p.ColN, s.ColN) ColN
FROM Patient a
LEFT JOIN ETT t
ON a.Patient_ID = t.Patient_ID
LEFT JOIN Phar p
ON a.Patient_ID = p.Patient_ID
LEFT JOIN SSC s
ON a.Patient_ID = s.Patient_ID
To further gain more knowledge about joins, kindly visit the link below:
Visual Representation of SQL Joins
For or - do not ise ||, use "or"
You cannot join with or, you need re-format your query.

Filtering query with join statement

I am using ColdFusion 8 to develop my company's website and would like to return a list of records (just the clientname field) from a table (dbo.clients) that has no match in a different table (dbo.fees) for the purpose of prompting the end-user to add a fee schedule for those companies. An example:
dbo.clients
CLIENT_ID CLIENT_NAME
1 Joe's Diner
2 Save-a-Lot
3 Family Meds
4 DiFazio's
dbo.fees
CID CLIENT_NAME FEE
1 Joe's Diner 25.000
2 Save-a-Lot 35.000
4 DiFazio's 30.000
What I desire is a resultset that, in the case of the above tables/data, would return only clientid/clientname 3/Family Meds because they do not have a fee listed/record in the table dbo.fees. My DB is MSSQL 2005. My query is:
SELECT clientid
FROM clients
INNER JOIN fees
ON clients.clientid <> fees.cid;
Which returns a Cartesian product of 50,000+ results. Using LEFT/RIGHT OUTER JOIN still gives me a Cartesian product and DISTINCT simply returns every record from dbo.clients regardless of whether or not they have a dbo.fees entry or not. What am I doing wrong?
p.s. Also of note: The admin before me apparently did not set up a PK/FK relationship between the clients/fees tables and so any query syntax that might be reliant on that may not work in this situation. It would probably have to work based solely on the values of the relevant fields.
You can use a LEFT JOIN with a WHERE clause that will return only those records that do not appear in the fees table:
select c.CLIENT_ID, c.CLIENT_NAME
from clients c
left join fees f
on c.CLIENT_ID = f.CLIENT_ID
where f.CLIENT_ID is null
If you need help learning JOIN syntax, here is a great reference:
A Visual Explanation of SQL Joins
This can also be written using a NOT EXISTS:
select *
from clients c
where not exists (select CLIENT_ID
from fees f
where c.CLIENT_ID = f.CLIENT_ID)
See SQL Fiddle Demo with both queries
Simplest, you could just use a NOT IN;
SELECT clientid FROM clients WHERE clientid NOT IN
(SELECT clientid FROM fees)
...or you can use a LEFT JOIN to do the same thing a bit more verbosely; f.clientid will be NULL if a fee does not exist for the client.
SELECT c.clientid
FROM clients c
LEFT JOIN fees f
ON c.clientid = f.clientid
WHERE f.clientid IS NULL

struggling with a left join in a nHibernate query

I'm struggling to replicate a simple sql left join in a nHibernate query. Other answers on SO have led me to be more confused as to what is the smartest way to tackle left joins in a domain query.
Example:
2 DB Tables:
Customer
CustId INT PK
Orders
OrderId INT PK
CustId INT FK
Status INT
1 SQL Query:
Select c.CustId from Customer c
left join Orders o on o.CustId = c.CustId and o.Status = 2
where o.OrderId is null
This will retrieve a unique list of Customers who don't have an order in status 2,
Note, it also includes customers who don't have an order at all.
This is a contrived example to simplify this question, but this type of query is very useful and not easy to do any other way.
Imagine nh mappings for "Customer" and "Orders" which simply reflect the example tables above.
Is there a simple way to extract my list of unique, non-status-2 customers in nHibernate, in a query, without resorting to a SQL query or ending up in a select n+1 scenario?
Query preferences:
1 linq-to-nhibernate
2 QueryOver
3 HQL
4 Criteria.
Thanks.
See http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/queryhql.html#queryhql-joins. It's the Hibernate reference, and not the nHibernate reference, but I'd assume they work the same (BTW, this post seems to confirm it):
You may supply extra join conditions using the HQL with keyword.
from Cat as cat
left join cat.kittens as kitten
with kitten.bodyWeight > 10.0
So, in your case, it should look like
select c.CustId from Customer c
left join Orders o with o.Status = 2
NHibernate 3.0 has an overload method for ICriteria .CreateAlias which takes 4 params, the last param is withClause.
Here is an example:
DetachedCriteria criteria = DetachedCriteria.For<Models.BO.Customer>("customer")
.CreateAlias(ReflectionHelper.PropertyName<Models.BO.Customer>(x => ((Models.BO.Interfaces.ICustomerQueryOnly) x).Tasks),
"activeTasks", JoinType.LeftOuterJoin, Restrictions.IsNotNull("activeTasks.LockedBy")
)
.CreateAlias(ReflectionHelper.PropertyName<Models.BO.Customer>(x => ((Models.BO.Interfaces.ICustomerQueryOnly) x).Tasks2),
"availableTasks", JoinType.LeftOuterJoin,
availableTasksRestraction
)
.Add(Restrictions.Eq("CustomerBase", _customerBase))
.Add(Restrictions.Eq("IsActive", true));
which endup with something like:
FROM Customers c
left join Tasks t on t.customerId = c.Id and (t.DeletedDate is null and
t.lockedById is null and [etc])
left join Tasks activetasks [etc]
where [...]
In this example I need to extract all customers and number of available tasks and number of active task for each customer.
If the entities are unrelated and you don't wish to map a relation, you can use a theta join. See here
Maybe something like
Select c from Customer c, Order o
where o.CustId = c.CustId and o.Status = 2