I ran into a problem with my T-SQL query. I have warehouse database, and I want to add currency exchange rates to my transactions, to see them in EUR and USD.
To do that, I am using Europe Central bank currency rates.
My query looks like this:
SELECT
Companys.Companys_name,
Warehouse_oper.Pavad_num,
[Items]![Quantity]*[Items]![Price] AS Expr1,
[Items]![Quantity]*[Items]![Price]*[Exchange_rates]![USD] AS Expr2
FROM
(Companys
LEFT JOIN
(Exchange_rates
RIGHT JOIN
Warehouse_oper ON Exchange_rates.Date = Warehouse_oper.Date)
ON Companys.Companys_num_d_b = Warehouse_oper.Companys_nr_d_b)
LEFT JOIN
Items ON Warehouse_oper.Warehouse_oper_num_d_b = Items.Warehouse_oper_num_d_b;
Sorry if its hard to understand, because I translated all variables to English.
Anyways this query works fine, if LEFT JOIN (Exchange_rates RIGHT JOIN Warehouse_oper ON Exchange_rates.Date = Warehouse_oper.Date, but bank does not provide them on holidays, so on those dates I have NULL values.
How can I edit this query (I know it's messy, but it's from Access) to SELECT most recent available date?
I tried:
LEFT JOIN
(Exchange_rates RIGHT JOIN Warehouse_oper ON
(SELECT TOP 1 Exchange_rates.Date FROM Exchange_rates WHERE
Exchange_rates.Date <= Warehouse_oper.Date) = Warehouse_oper.Date)
but with no success.
Related
I am using a similar query. I cannot post the actual query and the execution plans here. I tried adding an execution plan suggesting a non-clustered index but it slowed down the query further.
I know it's incomplete information, but can you please suggest what I can try please? I am out of options!!
I am putting the below condition in the where clause, the date seems fine but as soon as I add any of the other 2, the query takes hours. The where condition is used when I try to query the view.
where Date_Time between '2021-11-01 00:00:00.000' and '2022-11-02 00:00:00.000'
and Visit_code not in ('12', '13')
and mode_code <>'99'
Execution plan XML
CREATE VIEW [dbo].[vw_Test] AS
select fields
from table1 ed
left join table2 e on ed.field1_id = e.field1_id
left join table3 et on et.field1_id = ed.field1_id
left join table4 etf on etf.field1_id = e.field1_id
and etf.field2_cd= 85429041
and etf.dt_tm_field >= '2025-01-01 00:00:00.0000000'
left join table5 etf_dt on etf_dt.field1 = e.field1
and etf_dt.field3= 85429039
and etf_dt.dt_tm_field >= '2025-01-01 00:00:00.0000000'
left join table6 ei on ei.field1 = ed.field1
and ei.field4_cd = 123485.00
left join table7 cvo_ModeOfArrival on cvo_ModeOfArrival.field = ed.field6
and cvo_ModeOfArrival.field5 = 12345
left join table7 cvo_ModeOfSep on cvo_ModeOfSep.field = ei.field7
and cvo_ModeOfSep.field5 = 23456
left join table7 cvo_FinancialClass on cvo_FinancialClass.field = e.field8
and cvo_FinancialClass.field5 = 34567
left join table7 cvo_Specialty on cvo_Specialty.field = e.field9
and cvo_Specialty.field5 = 45678
left join table8 ea on ea.field1_id = e.field1_id
left join table7 cvo_ea on cvo_ea.field = ea.field10
and cvo_ea.field11 = 345666
GO
Looking at your code I can't see anything that can be improved in the context of T-SQL statement.
I will advice the following:
check each table and which columns you need in the fields part - it is possible the engine to be reading the whole row, instead the needed columns as index is missing; you can create nonclustered indexes in order to reduce the IO
check if any of these new indexes can be filtered index, as you have a lot of hard coded criteria (ei.field4_cd = 123485.00)
If the above is not enough, you may think of creating separate table for storing this information and populate it in advanced.
In order to debug, you can add the following line before the query:
SET STATISTICS IO ON;
and then past the results from the messages tab here - it will give you some details about for which tables most IO is consumed. You can start with them.
I would investigate breaking this query into multiple parts using derived tables. There are plenty of examples for this online. I always try to use SELECT TOP (2147483647) ....
I'm having issues with what I believe should be a simple problem in SQL Server 2017. I need to show the total sales price for a given sale. This is what I have written (note I deleted the totalprice sum formulae because it returned an error) :
USE [Antiques]
GO
DECLARE #TotalPrice INT
SELECT
Sales.SaleNo,
Sales.SalesDate,
Customers.FirstName,
Customers.LastName,
Products.Price,
#TotalPrice AS TotalPrice
FROM
Customers JOIN Sales ON Customers.CustomerID = Sales.CustomerID
JOIN SalesProducts ON Sales.SaleNo = SalesProducts.SaleNo
JOIN Products ON SalesProducts.ProductID = Products.ProductID
WHERE (Products.ProductID = SalesProducts.ProductID)
GO
This is the result:
Even if I remove the item price (which I have just put in temporarily and won't be in final code) there are still multiple lines per sale (1 for each item in the sale). Have I used the wrong joins? How can I get it looking like this:
Can anyone please tell me what I'm doing wrong? I've tried so many ways of using the Sum function and Group By and failing. (Note: this has to be a basic query and not a stored procedure unfortunately)
Actually you're not too far away. I'd move the grouping in a derived table and join that, to get the totalprice.
SELECT sales.saleno,
sales.salesdate,
customers.firstname,
customers.lastname,
x.totalprice
FROM sales
INNER JOIN customers
ON customers.customerid = sales.customerid
INNER JOIN (SELECT salesproducts.saleno,
sum(products.price) totalprice
FROM salesproducts
INNER JOIN products
ON products.productid = salesproducts.productid
GROUP BY salesproducts.saleno) x
ON x.saleno = sales.salesno;
We are in the healthcare business and we have a SQL database where we store the indications (how much care should the client receive in minutes) and the appointments (how much care have we delivered to the client in minutes).
The query i wrote is as follow:
SELECT
CF.ClientNr,
C.Name,
F.Description AS Function,
CF.Time AS Indication,
SUM(P.Minutes) As Production,
C.Insurance,
V.Name AS Team
FROM ClientFunctie AS CF
INNER JOIN Client AS C ON C.ClientNr=CF.ClientNr
INNER JOIN HoofdaanbiederFunctie AS H ON CF.HoofdaanbiederFunctieNr=H.HoofdaanbiederFunctieNr
INNER JOIN Functie AS F ON H.FunctieNr=F.FunctieNr
LEFT JOIN Planning AS P ON CF.ClientFunctieNr=P.ClientFunctieNr
LEFT JOIN DeclaratieAfhandeling AS D ON P.DeclaratieAfhandelingNr=D.DeclaratieAfhandelingNr
LEFT JOIN Vestiging AS V ON P.VestigingNr=V.VestigingNr
WHERE
D.StatusNr = 2 AND
CF.Einddatum > '2018-01-01' /*startdatum*/ AND
CF.Startdatum < '2018-01-28' /*einddatum*/ AND
CF.IsAkkoord = 1 AND
F.Omschrijving LIKE '%mwa%' AND
F.Omschrijving LIKE '%hv%'
GROUP BY
CF.ClientNr,
C.Name,
F.Description AS Function,
CF.Time AS Indication,
C.Insurance,
V.Name AS Team
My goal is to know how many minutes per indications have been delivered and how many indications have received 0 minutes.
Right now i only see the indications in my results with minutes but i also want to see which indications have 0 minutes. I tried to play with the left/right join but im right now out of options. I would really appreciate any help.
It is bit hard without table structure but here how I usually go.
I think I would extract the calculations in a subquery and edit the main query in consequence, something like that:
SELECT CF.ClientNr,
C.Name,
F.Description AS Function,
CF.Time AS Indication,
WL-Production As Production,
C.Insurance,
V.Name AS Team
FROM [...]
LEFT JOIN ( SELECT SUM(P.Minutes) As Production, CF.ClientNr as ClientNr
FROM ClientFunctie AS CF
INNER JOIN Planning AS P ON CF.ClientFunctieNr = P.ClientFunctieNr
INNER JOIN DeclaratieAfhandeling AS D ON P.DeclaratieAfhandelingNr = D.DeclaratieAfhandelingNr
WHERE D.StatusNr = 2
GROUP BY CF.ClientNr) AS WL ON CF.ClientFunctieNr = WL.ClientNr
(I do not have a SqlServer to test it out hopefully that will help)
You could use the same approach for counting the 0 minutes indications.
Also looking at your query it seems like you also need the name of the need Team who did the job, your queries might need some adjustments if you need the the total of time no matter which Team did the job.
SELECT
tbStok.sModel AS Kod, tbStok.sAciklama AS Adı,
SF.lFiyat AS SF, PSF.lFiyat AS PSF,
TL.lFiyat AS TL , USD.lFiyat AS USD
FROM
tbStok
LEFT JOIN
tbStokFiyati AS TL ON tbStok.nStokID = TL.nStokID
LEFT JOIN
tbStokFiyati AS SF ON tbStok.nStokID = SF.nStokID
LEFT JOIN
tbStokFiyati AS PSF ON tbStok.nStokID = PSF.nStokID
LEFT JOIN
tbStokFiyati AS USD ON tbStok.nStokID = USD.nStokID
GROUP BY
tbStok.sModel, tbStok.sAciklama, SF.lFiyat, PSF.lFiyat, TL.lFiyat,USD.lFiyat
Above is the SQL statement I'm using.
When query started, result is 7255470 rows but I have 18867 rows in tBstok table.
We have product information in tbStok table with 2 different columns such as product code and product name. And in the other table, called tbStokFiyati, there are 4 different columns which I need to get.
And result is very slow!
The table needs to be more than worth separating from tbStokFiyati.
SELECT
tbStok.sModel AS Kod, tbStok.sAciklama AS Adı,
SF.lFiyat AS SF, PSF.lFiyat AS PSF,
TL.lFiyat AS TL , USD.lFiyat AS USD
FROM tbStok
LEFT JOIN
tbStokFiyati AS TL ON tbStok.nStokID = TL.nStokID
and TL.sFiyatTipi='TL'
LEFT JOIN tbStokFiyati AS SF ON tbStok.nStokID = SF.nStokID
and SF.sFiyatTipi='SF'
LEFT JOIN tbStokFiyati AS PSF ON tbStok.nStokID = PSF.nStokID
and PSF.sFiyatTipi='PSF'
LEFT JOIN tbStokFiyati AS USD ON tbStok.nStokID = USD.nStokID
and USD.sFiyatTipi='USD'
GROUP BY
tbStok.sModel, tbStok.sAciklama, SF.lFiyat, PSF.lFiyat, TL.lFiyat,USD.lFiyat
The first things you should be revisit when running on this kind of performance issues is the database design. Have the PKs been defined accordingly? Have you created NON CLUSTERED INDEXes over each FK to seepd up the joins? Have you created indexes over interesting columns which are being used on your queries? There is a feature you can use on SQL Server Management Studio called Actual Execution Plan to examinate what's going wrong about the query's performance.
Please take a look to SQL Server Index Basics for further reference.
There also some util links for Basic and Advanced Execution Plan understanding:
* http://www.simple-talk.com/sql/performance/execution-plan-basics/
* http://www.mssqltips.com/sqlservertip/1856/sql-server-query-execution-plans-in-sql-server-management-studio/
The difference between Actual and Esitmated execution plan:
* http://blog.sqlauthority.com/2007/08/28/sql-server-actual-execution-plan-vs-estimated-execution-plan/
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.