How do I remove a nested select from this SQL statement - sql

I have the following SQL:
SELECT * FROM Name
INNER JOIN ( SELECT 2 AS item, NameInAddress.NameID as itemID, NameInAddress.AddressID
FROM NameInAddress
INNER JOIN Address ON Address.AddressID = NameInAddress.AddressID
WHERE (Address.Country != 'UK')
) AS Items ON (Items.itemID = Name .Name ID)
I have been asked to remove the nested select and use INNER JOINS instead, as it will improve performance, but I'm struggling.
Using SQL Server 2008
Can anyone help?
Thanks!

Your query is not correct as you're using Items.itemID while it's not in the subselect
I guess this is what you meant:
SELECT Name.*
FROM Name
INNER JOIN NameInAddress
ON Name.NameID = NameInAddress.NameID
INNER JOIN Address
ON Address.AddressID = NameInAddress.AddressID
WHERE (Address.Country != 'UK')
EDIT: The exact translation of your query would start with a SELECT Name.*, 2 as Item, NameInAddress.NameID, NameInAddress.AddressID though

It is one of those long-lived myths that nested selects are slower than joins. It depends completely on what the nested select says. SQL is just a declarative language to tell what you want done, the database will transform it into completely different things. Both MSSQL and Oracle (and I suspect other major engines as well) are perfectly able to transform correlated subqueries and nested views into joins if it is beneficial (unless you do really complex things which would be very hard, if possible, to describe with normal joins.

SELECT 2 AS Item, *
FROM Name
INNER JOIN NameInAddress
ON Name.NameID = NameInAddress.NameID
INNER JOIN Address
ON Address.AddressID = NameInAddress.AddressID
WHERE Address.Country != 'UK'
PS: Don't use "*". This will increase performance too. :)

Related

What is the best way to write inner join query in SQL?

First Way:
SELECT ST.PersonID, ST.CustomerID, ST.SaleTypeID, ST.PaymentGatewayID,
ST.CustomerMembershipID, ST.CustomerPaymentGatewayID, P.Currency
FROM ServiceTransaction ST
INNER JOIN dbo.Person P ON ST.PersonID = P.PersonID;
Second Way:
SELECT ST.PersonID, ST.CustomerID, ST.SaleTypeID, ST.PaymentGatewayID,
ST.CustomerMembershipID, ST.CustomerPaymentGatewayID, P.Currency
FROM ServiceTransaction ST
INNER JOIN dbo.Person P ON P.PersonID = ST.PersonID;
I want to optimize this query in SQL. Currently I am using second way and I need expert opinion, which one is best approach.
However, any one can add some new way to optimize this query as well.
As comments suggest, they are identical in many aspects. For a personal note tho if you keep the same format it gets easier to follow so I use the following schema to keep tabs on tables where I always use lower numbered table on left side
SELECT Column_list
FROM TABLE1
INNER JOIN TABLE2
INNER JOIN TABLE3
ON Table1.ColName = Table2.ColName
ON Table1.ColName = Table3.ColName | ON Table2.ColName = Table3.ColName
This way when you are working with multiple tables and joins it is easier to follow which table is joined where and which table was mentioned first in the query.

optimization select distinct query

How can i optimize this query,
how to rewrite a request through exists:
select DISTINCT
p.SBJ_ID,
nvl(l.ATTR,c.CODE) as ATTR,
l.VALUE
from T_TRFPRMLST p,
T_CMSATTR_LINK l,
C_SBJCONCEPT c
where l.SBJ_ID(+) = p.SBJ_ID
and p.sbj_id = c.ID;
Please use ANSI style join syntax, first of all.
Now, Coming to your question, according to my knowledge NVL perform worse when working with large data sets.
So how can we achieve the same functionality? -- We can use DECODE or CASE WHEN.
Among these two also, CASE WHEN will be better when it comes to performance.
Compare the execution plan of query mentioned in your question and the execution plan of the following query and you will definitely find the difference.
SELECT DISTINCT
P.SBJ_ID,
CASE
WHEN L.ATTR IS NOT NULL THEN L.ATTR
ELSE C.CODE
END AS ATTR,
L.VALUE
FROM
T_TRFPRMLST P
JOIN C_SBJCONCEPT C ON ( P.SBJ_ID = C.ID )
LEFT JOIN T_CMSATTR_LINK L ON ( P.SBJ_ID = L.SBJ_ID);
Please make sure that PKs and FKs are properly created and proper indexes are also available as indexes are created mainly for performance.
Cheers!!
You can't use exists here, because you are using more than 1 table columns in select.
And I understand you should use standard join keyword when joining tables.
select DISTINCT
p.SBJ_ID,
nvl(l.ATTR,c.CODE) as ATTR,
l.VALUE
from T_TRFPRMLST p
join T_CMSATTR_LINK l
on l.SBJ_ID = p.SBJ_ID
join C_SBJCONCEPT c
on p.sbj_id = c.ID;
I might be wrong in left/right as I am not much frequent with (+).
Hope this helps.

SQL Fieldname vs Aliasname

I have been trying to figure out why the following SQL works
SELECT c_Supplier.Supplier_ID AS A_ID, c_Supplier.Name, c_Supplier.RFC, c_Supplier_Direccion.Description, c_Supplier_Direccion.Address, c_Supplier_Phone.Phone
FROM c_Supplier LEFT JOIN (c_Supplier_Direccion LEFT JOIN c_Supplier_Phone ON c_Supplier_Direccion.Supplier_Direccion_ID = c_Supplier_Phone.Supplier_Direccion_ID) ON c_Supplier.Supplier_ID = c_Supplier_Direccion.Supplier_ID
WHERE (c_Supplier.Supplier_ID=1);
But when I try to use the aliasname (A_ID) in the WHERE clause, I got an error
SELECT c_Supplier.Supplier_ID AS A_ID, c_Supplier.Name, c_Supplier.RFC, c_Supplier_Direccion.Description, c_Supplier_Direccion.Address, c_Supplier_Phone.Phone
FROM c_Supplier LEFT JOIN (c_Supplier_Direccion LEFT JOIN c_Supplier_Phone ON c_Supplier_Direccion.Supplier_Direccion_ID = c_Supplier_Phone.Supplier_Direccion_ID) ON c_Supplier.Supplier_ID = c_Supplier_Direccion.Supplier_ID
WHERE (A_ID=1);
Any ideas?
I don't understand your question. This is a reasonably formed SQL query:
SELECT c_Supplier.Supplier_ID AS Entidad_ID, c_Supplier.Name,
c_Supplier.RFC, c_Supplier_Direccion.Description,
c_Supplier_Direccion.Address, c_Supplier_Phone.Phone
FROM c_Supplier LEFT JOIN
(c_Supplier_Direccion LEFT JOIN
c_Supplier_Phone
ON c_Supplier_Direccion.Supplier_Direccion_ID = c_Supplier_Phone.Supplier_Direccion_ID
) ON c_Supplier.Supplier_ID = c_Supplier_Direccion.Supplier_ID
WHERE (c_Supplier.Supplier_ID = 1);
(I would recommend table aliases for readability, but that is a separate issue.)
It has no alias called A_ID anywhere in the query, so there is no reason to ever expect a reference to A_ID to work (unless it is a column in one of the tables).
And, SQL doesn't allow the re-use of table aliases in the SELECT where they are defined or the WHERE clause. This is not an MS Access limitation; it is how the SQL language is defined.
If you want to do so in MS Access, you can use a subquery and reference the table alias in the outer query.

Sub query select statment vs inner join

I'm confused about these two statements who's faster and more common to use and best for memory
select p.id, p.name, w.id, w.name
from person p
inner join work w on w.id = p.wid
where p.id in (somenumbers)
vs
select p.id, p.name, (select id from work where id=p.wid) , (select name from work where id=p.wid)
from person p
where p.id in (somenumbers)
The whole idea of this is that if I have I huge database and I want to make inner join it will take memory and less performance to johin work table and person table but the sub query select statments it will only select one statment at the time so which is the best here
First, the two queries are not the same. The first filters out any rows that have no matching rows in work.
The equivalent first query uses a left join:
select p.id, p.name, w.id, w.name
from person p left join
work w
on w.id = p.wid
where p.id in (somenumbers);
Then, the second query can be simplified to:
select p.id, p.name, p.wid,
(select name from work where w.id = p.wid)
from person p
where p.id in (somenumbers);
There is no reason to look up the id in work when it is already present in person.
If you want optimized queries, then you want indexes on person(id, wid, name) and work(id, name).
With these indexes, the two queries should have basically the same performance. The subquery will use the index on work for fetching the rows from work and the where clause will use the index on person. Either query should be fast and scalable.
The subqueries in your second example will execute once for every row, which will perform badly. That said, some optimizers may be able to convert it to a join for you - YMMV.
A good rule to follow in general is: much prefer joins to subqueries.
joins give better performance as comparison with sub-query .if there is join on Int column or have index on join column gives best performance .
select p.id, p.name, w.id, w.name
from person p
inner join work w on w.id = p.wid
where p.id in (somenumbers)
It really depends on how you want to optimaze the query (includie but not limited to add/removing/reordering the index),
I found the setup which makes join soars might let subquery suffer, the opposite may also be true. Thus there is not that much point to compare them with the same setup.
I choose to use and optimize with join. In my experince join at its best condition setup, rarely loses to subquery, but a lot eaiser to read.
When the vendor stuff an extreme load of queries with subqueries to the system. Unless the performance start to crawl, due to my other work's query optimization, it simply doesn't worth the effort to change them.

Error when left joining two databases (SQL Server)

I have a great problem with joining two MSSQL databases together (on the same server) using LEFT JOIN. I run this SQL from the database OLAB_DB and get the error:
The multi-part identifier "OLAP_DB.dbo.OLAP_invoice.UserID" could not be bound.
There seem to be a problem with the DB not being able to find itself, and I have no idea of how to solve this. I have double and triple checked the spelling and rewrote the SQL several times, but now I just have to give up and ask for help :(
This doesn't work:
SELECT TOP 200
COALESCE(LTRIM(RTRIM(contact_db.dbo.ContactTable.EmailAdr)),LTRIM(RTRIM(contact_db.dbo.CustomerTable.EmailAdr))) AS EMAIL,
OLAP_invoice.OrdreLinjeID AS ORDERNO
OLAP_invoice.SalgsPris AS PRICE,
OLAP_invoice.UserID AS CONTACTID
FROM OLAP_invoice,contact_db.dbo.CustomerTable
LEFT JOIN contact_db.dbo.ContactTable
ON OLAP_DB.dbo.OLAP_invoice.UserID = contact_db.dbo.ContactTable.UserID
WHERE contact_db.dbo.CustomerTable.ClientID = OLAP_invoice.ClientID
But skipping the left join and just getting data from the two different databases works just fine.
This works just fine:
SELECT TOP 200
LTRIM(RTRIM(contact_db.dbo.CustomerTable.EmailAdr)) AS EMAIL,
LTRIM(RTRIM(contact_db.dbo.ContactTable.UserID)) AS EMAIL2,
OLAP_invoice.OrdreLinjeID AS ORDERNO
OLAP_invoice.SalgsPris AS PRICE,
OLAP_invoice.UserID AS CONTACTID
FROM OLAP_invoice,contact_db.dbo.CustomerTable
WHERE contact_db.dbo.CustomerTable.ClientID = OLAP_invoice.ClientID
AND contact_db.dbo.ContactTable.UserID = OLAP_invoice.UserID
The reason I need the LEFT JOIN, is because some orders are not registered with a UserID (only ClientID).
I have checked the access rights and there is no problem to access the fields individually, the problem occurs when I have to compare the values in the LEFT JOIN and specifies the absolute path.
Do you have any idea of what can be wrong?
You can try this:
SELECT TOP 200 COALESCE(LTRIM(RTRIM(contact_db.dbo.ContactTable.EmailAdr)),LTRIM(RTRIM(contact_db.dbo.CustomerTable.EmailAdr))) AS EMAIL,
OLAP_invoice.OrdreLinjeID AS ORDERNO
OLAP_invoice.SalgsPris AS PRICE,
OLAP_invoice.UserID AS CONTACTID
FROM OLAP_invoice LEFT JOIN contact_db.dbo.ContactTable ON OLAP_DB.dbo.OLAP_invoice.UserID = contact_db.dbo.ContactTable.UserID, contact_db.dbo.CustomerTable
WHERE contact_db.dbo.CustomerTable.ClientID = OLAP_invoice.ClientID
You are selecting from OLAP_invoice, but joining to OLAP_DB.dbo.OLAP_invoice. You need to qualify the table exactly the same every time, or use an alias.
So either:
FROM OLAP_DB.dbo.OLAP_invoice
left join contact_db.dbo.ContactTable
on OLAP_DB.dbo.OLAP_invoice...
OR
FROM ROM OLAP_invoice
LEFT JOIN ontact_db.dbo.ContactTable
ON OLAP_invoice...
Or you could use an alias as well, less typing that way.
FROM OLAP_invoice OI
LEFT JOIN ontact_db.dbo.ContactTable CT
ON OI...
Personally, I try to avoid having multiple tables in my FROM without intentionally specifying the type of join.
I find something like this to be much more readable and maintainable :
SELECT TOP 200
COALESCE( LTRIM(RTRIM(con.EmailAdr)), LTRIM(RTRIM(cus.EmailAdr)) ) AS EMAIL,
i.OrdreLinjeID AS ORDERNO
i.SalgsPris AS PRICE,
i.UserID AS CONTACTID
FROM OLAP_invoice i
LEFT JOIN contact_db.dbo.CustomerTable cus ON cus.ClientID = i.ClientID
LEFT JOIN contact_db.dbo.ContactTable con ON con.UserID = i.UserID