Cross querys with CTE into single query (MSSQL) - sql-server

Good afternoon,
I've 2 tables into my SQL DB, in the first I've the asignation for days to a person, and other the registry per day of this person, I will like see if this person have or not registry for each day into the range of specification.
I've encountered a query that uses CTE for return the range in days independent, and other query in that I've the registry group by person and day, but I can't cross these queries.
Bottom there is a picture with queries and results of each.
Thanks.
My SQL querys

You may use several CTEs in one statement, so you may put each query in separate CTE and join them later lake that:
SELECT
p.cedula, p.starttime,
r.Descr, r.Candidad
FROM ctePeriod p
LEFT JOIN cteRegistry r on r.cedula = p.cedula AND r.Dia = p.StartTime
ORDER BY p.cedula, p.starttime
all above as a single query.
Another way is to put results of your Query1 and Query2 into temp tables and build your final query on those temp tables e.g.:
SELECT DISTINCT ...
INTO #Period
FROM CTE
WHERE ...
SELECT ...
INTO #Registro
FROM Registro
GROUP BY ...
SELECT
p.cedula, p.starttime,
r.Descr, r.Candidad
FROM #Period p
LEFT JOIN #Registro r on r.cedula = p.cedula AND r.Dia = p.StartTime
ORDER BY p.cedula, p.starttime

Related

SQL Server Using sub query in JOIN statements

Does JOINING of tables more easy to read or faster to execute if I create a sub query and a select statement with only the columns needed for the entire query?
-- Example
SELECT s.Id,
s.TransactionDate,
s.TransactionNo,
s.CustomerId,
s.SiteLocationId,
s.SubTotal,
sd.ItemId,
sd.UnitPrice,
sd.GrossAmount
FROM tblTransactions s
LEFT OUTER JOIN tblTransactionDetails sd ON sd.TransactionId = s.Id
Compare to this:
SELECT s.Id,
s.TransactionDate,
s.TransactionNo,
s.CustomerId,
s.SubTotal,
sd.ItemId,
sd.UnitPrice,
sd.GrossAmount
FROM tblTransactions s
LEFT OUTER JOIN (
SELECT TransactionId,
ItemId,
UnitPrice,
GrossAmount
FROM tblTransactionDetails
) sd ON sd.TransactionId = s.Id
What are the advantages and disadvantages of each example given? I am also trying to reduce the percentage read of the Details in the Execution Plan.
I think that SQL Server creates the same execution plan for both queries. If you want to increase the performance due to the column selection, you should create a non-clustered index. Then, the query optimizer should use the more compact index instead the table.
CREATE NONCLUSTERED INDEX ix_tblTransactionDetails_test
ON tblTransactionDetails (TransactionId) INCLUDE (ItemId, UnitPrice, GrossAmount)

Need query to determine number of attachments for each issue

I have a database in SQL Server that has three tables: Issues, Attachments, and Requestors. I need a single query that returns all the columns contained in the "Issues" and "Attachments" tables. Listed below is the query that I've created, but it's not working as expected:
SELECT A.*,
B.*,
SubQuery.attachmentcount
FROM [DB].[dbo].[issues] AS A
FULL OUTER JOIN [DB].[dbo].[requestors] AS B
ON A.issue_id = B.issue_id,
(SELECT Count(attachments.attachment_id) AS AttachmentCount
FROM issues
LEFT OUTER JOIN attachments
ON issues.issue_id = attachments.issue_id
WHERE attachments.attachment_status = 1
GROUP BY issues.issue_id) AS SubQuery;
Pictures describing the three tables are listed below:
Any ideas on how to fix my query?
Thanks,
"I need a single query that returns all the columns contained in the "Issues" and "Attachments" tables".
Based on this sentence try this:
SELECT A.Issue_ID, I.Issue_Name,r.Name, COUNT(A.attachment_id) AS Count
FROM Attachments as A
INNER JOIN Issues I on I.issue_id = A.issue_id
INNER JOIN requestors as R on A.issue_id = R.requestor_id
WHERE A.attachment_status = 1
GROUP BY A.Issue_ID, I.Issue_Name, r.Name
--Specify all columns by name (don't use *)
Keep It Simple and Try This!
SELECT i.Issue_ID, i.Issue_Name, COUNT(a.attachment_id) AS AttachmentCount
FROM attachments a JOIN
issues i ON
i.issue_id = a.issue_id
WHERE a.attachment_status = 1
GROUP BY i.Issue_ID, i.Issue_Name
Add your Desired Columns in Both Select List and Group By Clause and you are done.

SQL Server last date

Is there an option for getting the row with the highest date without joining the same table and use max(date) ?? Is Top1 order by desc a valid option ?
I use SQL Server 2000. And performance is important.
edit:
Table1:
columns: part - partdesc
Table 2:
columns: part - cost - date
select a.part,partdesc,b.cost
left join( select cost,part
right join(select max(date),part from table2 group by part) maxdate ON maxdate.date = bb.date
from table2 bb ) b on b.part = a.part
from table1
I don't know if the code above works but that is the query I dislike. And seems to me inefficient.
Here's a somewhat simplified query based on your edit.
SELECT
a.part,
a.partdesc,
sub.cost
FROM
Table1 A
INNER JOIN
(SELECT
B.part,
cost
FROM
Table2 B
INNER JOIN
(SELECT
part,
MAX(Date) as MaxDate
FROM
Table2
GROUP BY
part) BB
ON bb.part = b.part
AND bb.maxdate = b.date) Sub
ON sub.part = a.part
The sub-sub query will hopefully run a little bit quicker than your current version since it'll run once for the entire query, not once per part value.
SELECT TOP 1 columnlist
FROM table
ORDER BY datecol DESC
is certainly a valid option, assuming that your datacols are precise enough that you get the results needed (in other words, if it's one row per day, and your date reflects that, then sure. If it's several rows per minute, you may not be precise enough).
Performance will depend on your indexing strategy and hardware.

SQL Query question

No particular DBMS in mind, how would I do the following:
# There are many tables per one restaurant, many napkins per one table
# Pseudo SQL
SELECT RESTAURANT WHERE ID = X;
SELECT ALL TABLES WHERE RESTAURANT_ID = RESTAURANT.ID;
SELECT ALL NAPKINS WHERE TABLE_ID = TABLE.ID;
But, all in one query? I've used a JOIN to get all the tables in the same query as restaurant, but is it possible to get all napkins for each table as well, in the same query?
select * -- replace * with the columns you need...
from restaurant as r
inner join tables as t on t.restaurant_id = r.id
inner join napkins as n on n.table_id = t.id
where r.id = [restaurant id]
You would definitely end up in repeating Tables and restaurant information on the rows, like:
Restaurant1 Table1 Napkin1
Restaurant1 Table1 Napkin2
Restaurant1 Table1 Napkin3
Restaurant1 Table2 Napkin4
Restaurant2 Table1 Napkin5
It seems you want to return three separate results, not a single result with repeat values for RESTAURANT_N or TABLE_N.
In SQL, this is done with stored procedures which can return multiple result sets. The syntax for stored procedures varies among database products, therefore you should ask the question for specific products. In the stored procedure, there will be three select statements for the RESTAURANTS, TABLES and NAPKINS. The results of the three statements are returned in a bundle to the application, which can then use the results.

Performance problem on a query

I have a performance problem on a query.
First table is a Customer table which has millions records in it. Customer table has a column of email address and some other information about customer.
Second table is a CommunicationInfo table which contains just Email addresses.
And What I want in here is; how many times the email address in CommunicationInfo table repeats in Customers table. What could be the the most performer query.
The basic query that I can explain this situation is;
Select ci.Email, count(*) from Customer c left join
CommunicationInfo ci on c.Email1 = ci.Email or c.Email2 = ci.Email
Group by ci.Email
But sure, it takes about 5, 6 minutes in execution.
Thanks in Advance.
this query is about as good as it gets if you have an index on Customer.Email and another on CommunicationInfo.Email
Select
c.Email, count(*)
from Customer c
left join CommunicationInfo ci on c.Email1 = ci.Email
left join CommunicationInfo ci2 on c.Email2 = ci2.Email
Group by c.Email
You mention:
And What I want in here is; how many
times the email address in
CommunicationInfo table repeats in
Customers table. What could be the the
most performer query.
To me, that sounds like you could easily use an INNER JOIN - this would most likely be a lot faster, since it will limit the search scope to just those customers who really do have an e-mail - anyone who doesn't have an e-mail at all (and thus a count(*) = 0) will not even be looked at - that might make a big difference even just in the number of rows SQL Server has to count and group.
So try this:
SELECT
ci.Email, COUNT(*)
FROM
dbo.Customer c
INNER JOIN dbo.CommunicationInfo ci
ON c.Email1 = ci.Email OR c.Email2 = ci.Email
GROUP BY
ci.Email
How does that perform in your case??
Using the OR condition robs the optimizer of opportunity to use HASH JOIN or MERGE JOIN.
Use this:
SELECT ci.Email, SUM(cnt)
FROM (
SELECT ci.Email, COUNT(c.Email) AS cnt
FROM CommunicationInfo ci
LEFT JOIN
Customer c
ON c.Email1 = ci.Email
GROUP BY
ci.Email
UNION ALL
SELECT ci.Email, COUNT(c.Email) AS cnt
FROM CommunicationInfo ci
LEFT JOIN
Customer c
ON c.Email2 = ci.Email
GROUP BY
ci.Email
) q2
GROUP BY
ci.Email
or this:
SELECT ci.Email, COUNT(*)
FROM CommunicationInfo ci
LEFT JOIN
(
SELECT Email1 AS email
FROM Customer c
UNION ALL
SELECT Email2
FROM Customer
) q
ON q.Email = ci.Email
GROUP BY
ci.Email
Make sure that you have indexes on Customer(Email) and Customer(Email2)
The first query will be more efficient if your emails are mostly not filled, the second one — if most emails are filled.
Depending on your environment there may not be much you can do to optimize this.
A couple of questions:
How many records in CommunicationInfo?
How often do you really need to run this query? Is it a one time analysis, or are multiple people going to be running this every 10 minutes?
Are the fields indexed? I'll make a guess that neither Email1 nor Email2 field is indexed. However, I wouldn't suggest adding an index without taking the balance of the whole system into consideration.
Why are you using a left join? Do you really need EVERYTHING from the Customer table? You're counting, so no harm in doing an INNER JOIN.
Suggestions:
Run the query through the Query Optimization wizard to see if there is anything SQL Server would recommend.
An extreme suggestion would be to dump the Email1 and Email2 columns into a temp table and join to that. I've seen queries run slowly because of a large amount of stress on a particular table, so sometimes copying the records into a temp table is faster, but this technique is very dependent on how much memory there is, how fast IO is, and the amount of stress on a particular table.

Resources