Is there a option to clean this SQL query up - sql

I was wondering if it was possible to make this query smaller
SELECT Templates.TempName
,TimeSpans.TimeSpan
,TemplateSlotTypes.[Type]
,TemplateSlots.Potition
,TemplateSlots.duration
FROM TimeSpans
INNER JOIN Templates ON Templates.TimeSpanId = TimeSpans.Id
INNER JOIN TemplateSlots ON Templates.Id = TemplateSlots.TemplateId
INNER JOIN TemplateSlotTypes ON TemplateSlots.[Type] = TemplateSlotTypes.Id

It seems that you need all the parts of this query, so there's nothing that can just be dropped from the query.
You could, however, use table aliases to reduce the amount of text:
SELECT t.TempName, tsp.TimeSpan, tst.[Type], ts.Potition, ts.duuration
FROM TimeSpans tsp
INNER JOIN Templates t ON t.TimeSpanId = tsp.Id
INNER JOIN TemplateSlots ts ON t.Id = ts.TemplateId
INNER JOIN TemplateSlotTypes tst ON ts.[Type] = tst.Id

Table aliases will make the joins less verbose, but assuming the field names are unique to the tables involved you don't need to prefix them with the table name.
SELECT TempName
,TimeSpan
,[Type]
,Potition
,duration
FROM TimeSpans ts
INNER JOIN Templates t ON t.TimeSpanId = ts.Id
INNER JOIN TemplateSlots s ON t.Id = s.TemplateId
INNER JOIN TemplateSlotTypes st ON s.[Type] = st.Id
However, I would recommend the use of a good IDE for SQL query development where it performs the joins for you and removes a lot of the typing.
Manually reducing the amount of text in a query is a false economy in the long run. It can actually make the SQL harder to read, and therefore more time consuming to modify or debug in the future.

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.

Odd Outer Joining Structure for a View

I am importing a view from an old database as part of a software upgrade and I saw this FROM clause as I was working.
FROM
t_store_master AS STM
RIGHT OUTER JOIN
dbo.t_shipping AS SHP
INNER JOIN
t_hu_master AS HUM
INNER JOIN
t_stored_item AS STO ON HUM.hu_id = STO.hu_id
ON SHP.shipment_id = HUM.reserved_for
AND SHP.location_id = HUM.location_id
INNER JOIN
dbo.t_carrier AS CAR ON SHP.carrier_code = CAR.carrier_code
LEFT OUTER JOIN
dbo.t_order_detail AS ORD
INNER JOIN
dbo.t_order AS ORM ON ORD.order_number = ORM.order_number
INNER JOIN
dbo.t_pick_detail PDL ON ORD.order_number = PDL.order_number
ON STO.type = PDL.pick_id
ON STM.store_id = HUM.control_number_2
It is my understanding that OUTER JOIN requires an ON clause in order to be interpreted properly by the compiler. However, there must be some edge case scenarios I am unaware of because the code above returns good data without throwing any errors.
After some goggling and reading up on MSDN standards for OUTER JOINs, I am still at a loss for what the LEFT OUTER JOIN and RIGHT OUTER JOIN are doing in this query.
I do know that the multiple ON clauses beneath the INNER JOINs are necessary. There seems to be some kind of hidden or implied mapping being done between the ON clauses and the OUTER JOINs. Past that I cannot tell what the purpose of writing a query this way would be.
Could someone shed some insight on how this works and why it would be written this way?
This is allowed. It makes slightly more sense with parentheses:
FROM t_store_master STM RIGHT OUTER JOIN
(dbo.t_shipping SHP INNER JOIN
(t_hu_master HUM INNER JOIN
t_stored_item STO
ON HUM.hu_id = STO.hu_id
)
ON SHP.shipment_id = HUM.reserved_for AND
SHP.location_id = HUM.location_id
) INNER JOIN
(dbo.t_carrier CAR
ON SHP.carrier_code = CAR.carrier_code LEFT OUTER JOIN
((dbo.t_order_detail ORD INNER JOIN
dbo.t_order ORM
ON ORD.order_number = ORM.order_number
) INNER JOIN
dbo.t_pick_detail PDL
ON ORD.order_number = PDL.order_number
)
ON STO.type = PDL.pick_id
)
ON STM.store_id = HUM.control_number_2
That said, I would recommend never writing a query like this and rewriting the query ASAP if it is in production code. At the very least, add the parentheses!
Parentheses are almost never needed in the FROM clause to express JOINs (there is one case where I do happen to use them). Non-interleaved ON clauses are never needed -- or at least, I have never had occasion to use them or think they were the best way to write a query. But, both are allowed.

Have merge Cartesian Join with high cost

We were querying the DB to populate some logged tickets, however the query formed causing the above issue and is communicated by our performance team.
Here I am into Java programming and I don't have much idea on these joins. How can I the re-frame below piece of query to avoid the merge Cartesian Join with high cost?
FROM
SERVICE_REQ SR,
SR_COBRAND_DATA SR_COB_DATA,
REPOSITORY rep,
SR_ASSIGNEE_INFO ASSIGNEE_INFO
WHERE
SR.SR_COBRAND_ID=rep.COBRAND_ID
AND SR.SERVICE_REQ_ID=SR_COB_DATA.SERVICE_REQ_ID (+)
AND SR.SERVICE_REQ_ID = ASSIGNEE_INFO.SERVICE_REQ_ID (+)
AND SR.SR_COBRAND_ID = 99
Create a composite index on columns SR_COBRAND_ID and SERVICE_REQ_ID of table SERVICE_REQ
-- Create Index [indexname] on SERVICE_REQ (SR_COBRAND_ID , SERVICE_REQ_ID);
Just a suggestion: you should not use old implicit join syntax but join explicit join syntax:
SELECT *
FROM SERVICE_REQ SR
LEFT JOIN SR_COBRAND_DATA SR_COB_DATA ON SR.SERVICE_REQ_ID=SR_COB_DATA.SERVICE_REQ_ID
INNER JOIN REPOSITORY rep ON SR.SR_COBRAND_ID=rep.COBRAND_ID
LEFT JOIN SR_ASSIGNEE_INFO ASSIGNEE_INFO ON SR.SERVICE_REQ_ID = ASSIGNEE_INFO.SERVICE_REQ_ID
WHERE SR.SR_COBRAND_ID = 99
Anyway, based on this condition you have not a Cartesian product between the table but a left join for SERVICE_REQ with SR_COBRAND_DATA and SR_ASSIGNEE_INFO reduce by inner join with REPOSITORY.
Perhaps to explain you goal you should add proper sample data, the expected result, and your actual result.

Condition on main table in inner join vs in where clause

Is there any reason on an INNER JOIN to have a condition on the main table vs in the WHERE clause?
Example in INNER JOIN:
SELECT
(various columns here from each table)
FROM dbo.MainTable AS m
INNER JOIN dbo.JohnDataRecord AS jdr
ON m.ibID = jdr.ibID
AND m.MainID = #MainId -- question here
AND jdr.SentDate IS NULL
LEFT JOIN dbo.PTable AS p1
ON jdr.RecordID = p1.RecordID
LEFT JOIN dbo.DataRecipient AS dr
ON jdr.RecipientID = dr.RecipientID
(more left joins here)
WHERE
dr.lastRecordID IS NOT NULL;
Query with condition in WHERE clause:
SELECT
(various columns here from each table)
FROM dbo.MainTable AS m
INNER JOIN dbo.JohnDataRecord AS jdr
ON m.ibID = jdr.ibID
AND jdr.SentDate IS NULL
LEFT JOIN dbo.PTable AS p1
ON jdr.RecordID = p1.RecordID
LEFT JOIN dbo.DataRecipient AS dr
ON jdr.RecipientID = dr.RecipientID
(more left joins here)
WHERE
m.MainID = #MainId -- question here
AND dr.lastRecordID IS NOT NULL;
Difference in other similar questions that are more general whereas this is specific to SQL Server.
In the scope of the question,
Is there any reason on an INNER JOIN to have a condition on the main
table vs in the WHERE clause?
This is a STYLE choice for the INNER JOIN.
From a pure style reflection point of view:
While there is no hard and fast rule for STYLE, it is generally observed that this is a less often used style choice. For example that might generally lead to more challenging maintenance such as if someone where to remove the INNER JOIN and all the subsequent ON clause conditions, it would effect the primary table result set, OR make the query more difficult to debug/understand when it is a very complex set of joins.
It might also be noted that this line might be placed on many INNER JOINS further adding to the confusion.

Refactor SQL (workaround RIGHT OUTER JOIN)

Since SQLite does not support RIGHT OUTER JOINS I pose the following challenge (read: invitation to do my work for me):
Refactor this query so it no longer utilises SQLite-unsupported constructs like RIGHT/FULL OUTER JOINs.
SELECT strings.*, translations.text
FROM translations INNER JOIN
language ON translations.language_id = language.id RIGHT OUTER JOIN
strings ON translations.string_id = strings.id
WHERE (language.handle = 'english')
I sense it can be achieved with subqueries or by pivoting the tables and performing a LEFT OUTER JOIN but my attempts have failed; my SQL's not what it used to be.
Here's a query builder outline showing the applicable schema: http://dl.getdropbox.com/u/264612/sql-refactor.PNG
First to crack it gets an e-hug from dekz
The following is untested.
select strings.*, translations.text
from strings left outer join translations
on translations.string_id = strings.id
and translations.language_id = (select id
from language
where language.handle = 'english')
I think this will give you all strings with the matching translation text where a suitable translation exists in English. Is that what you are trying to get?
Intriguing that SQLite allows LEFT OUTER JOINs but not RIGHT OUTER JOINs. Well, since it does allow LEFT OUTER JOINs, you're right, you can just rearrange the join order:
SELECT strings.*, translations.text
FROM strings LEFT OUTER JOIN (
translations INNER JOIN language ON translations.language_id = language.id
) tr ON tr.string_id = strings.id
WHERE (language.handle = 'english')
[EDIT: Applied Blorgbeard's suggestion of naming the joined table to get the query to parse -- hope it works now!]