UPDATE all records from existing SELECT query - sql

I have query to select data from related tables.
SELECT
s.id,
CASE
WHEN count(DISTINCT e.id) <> 0
THEN count(DISTINCT o.id) / count(DISTINCT e.id)
END OrdersAverageNumber
FROM
[School] s
JOIN
[SchoolStore] ss ON ss.SchoolId = s.Id
JOIN
[Event] e ON e.SchoolId = ss.SchoolId
AND e.IsDeleted = 0
AND e.Status = 1
AND e.Date >= #startDate
AND e.Date <= #endDate
JOIN
[Order] o ON o.EventId = e.id
AND o.OrderStatus = 1
AND o.CreatedDate >= #startDate
AND o.CreatedDate <= #endDate
GROUP BY
s.id;
But I can't understand what I need to change to update all OrdersAverageNumber records in School table with values from selection above.

You can use update:
with q as (< your query here >)
update s
set OrdersAverageNumber = q.OrdersAverageNumber
from school s join
q
on s.id = q.id;

Related

Multiply an aggregate function SUM with a column?

Is there a way to multiply an aggregate function? I need to multiply SUM(ma.gewight) for every article (an article is, for example, H114972 which is iron and is 32,1 meters) so the GROUP BY groups all same articles and for every different article I need to multiply a different number (the column that I am using to multiply is e.best_wert which is the meters, mentioned above). So basically I need to multiply the SUM(ma.gewicht) with e.best_wert - but it doesn't work.
PS. Gewicht = weight
PSS. e.best_wert = weight value/meters
SELECT m.artikel, COUNT(ei.bestell_po) bestell_po_menge, SUM(ma.gewicht) AS summe_gewicht--, SUM(e.best_wert*ma.gewicht) AS summe_kg
FROM MATV030 m
INNER JOIN EINV030 e ON e.BESTELL_NR = m.BESTELL_NR
INNER JOIN EINV035 ei ON e.bestell_nr = ei.bestell_nr
INNER JOIN MATV010 ma ON m.ARTIKEL = ma.ARTIKEL
WHERE e.lieferant = '6000176' AND m.menge_buch <> 0
--AND m.artikel = 'H114972'
AND m.bs = 'WE' AND m.budatum >= '20190101' AND m.budatum < '20190201'
GROUP BY m.artikel, ma.gewicht
ORDER BY m.artikel ASC
Try like this
SELECT m.artikel, COUNT(ei.bestell_po) bestell_po_menge, SUM(ma.gewicht) AS summe_gewicht, (e.best_wert * SUM(ma.gewicht)) AS summe_kg
FROM MATV030 m
INNER JOIN EINV030 e ON e.BESTELL_NR = m.BESTELL_NR
INNER JOIN EINV035 ei ON e.bestell_nr = ei.bestell_nr
INNER JOIN MATV010 ma ON m.ARTIKEL = ma.ARTIKEL
WHERE e.lieferant = '6000176' AND m.menge_buch <> 0
--AND m.artikel = 'H114972'
AND m.bs = 'WE' AND m.budatum >= '20190101' AND m.budatum < '20190201'
GROUP BY m.artikel, e.best_wert
ORDER BY m.artikel ASC
Try this,
;With CTE as
(
SELECT ma.ARTIKEL, SUM(ma.gewicht) AS summe_gewicht--, SUM(e.best_wert*ma.gewicht) AS summe_kg
FROM MATV030 m
INNER JOIN MATV010 ma ON m.ARTIKEL = ma.ARTIKEL
WHERE m.menge_buch > 0
--AND m.artikel = 'H114972'
AND m.bs = 'WE' AND m.budatum >= '20190101' AND m.budatum < '20190201'
GROUP BY m.ARTIKEL
--ORDER BY m.artikel ASC
)
SELECT m.artikel, COUNT(ei.bestell_po) bestell_po_menge,summe_gewicht, summe_gewicht*e.best_wert AS summe_kg
FROM CTE C
inner join MATV030 m on m.artikel=c.artikel
INNER JOIN EINV030 e ON e.BESTELL_NR = m.BESTELL_NR
INNER JOIN EINV035 ei ON e.bestell_nr = ei.bestell_nr
WHERE e.lieferant = '6000176'
GROUP BY m.artikel
ORDER BY m.artikel ASC
You can create A CTE (Common Table Expression) table with your aggregate values and then multiply both the tables using CTE.

SQL Server: query optimization

I have the following query which takes around 4 minutes to execute.
DECLARE #tdate DATETIME = '2019-09-01 00:00:00.000'
SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h
ON c.id = h.clid
WHERE h.status = 1
AND h.connect_radius IS NOT NULL
AND c.status = 1
AND h.type = 'Residential'
AND h.holdinNo NOT IN (SELECT holdingNo
FROM [db_land].[dbo].tbl_bill
WHERE year(date_month) = YEAR(#tdate)
AND MONTH(date_month) = MONTH(#tdate)
AND ( update_by IS NOT NULL
OR ispay = 1 ))
I found the inner join takes only few seconds.
SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h
ON c.id = h.clid
WHERE h.status = 1
AND h.connect_radius IS NOT NULL
AND c.status = 1
AND h.type = 'Residential'
It's the NOT IN checking which takes a lot of time. How I can optimize this query? For me it's needed to execute the query at least with in minute.
Make sure the WHERE and JOIN clause predicates are sargable. Applying a function to a column (e.g. YEAR(date_month)) prevents indexes on the column from being used efficiently.
Try this expression instead to avoid the functions. There are other methods depending on the SQL Server version.
WHERE
date_month >= DATEADD(day, 1, DATEADD(month, -1, EOMONTH(#tdate)))
AND date_month < DATEADD(day, 1, DATEADD(month, 1, EOMONTH(#tdate)))
Try by replacing NOT IN with a LEFT JOIN of the table [db_land].[dbo].tbl_bill on all the conditions and adding in the WHERE clause holdingNo is null so the returned rows are the non matching rows:
select c.id as clid, h.id as hlid,h.holdinNo, c.cliendID, c.clientName, h.floor, h.connect_radius
from [db_land].[dbo].tbl_client as c
inner join [db_land].[dbo].tx_holding as h
on c.id= h.clid
left join [db_land].[dbo].tbl_bill as b
on b.holdingNo = h.holdinNo and year(b.date_month) = YEAR(#tdate) and MONTH(b.date_month) = MONTH(#tdate)
and (b.update_by is not null or b.ispay = 1)
where h.status = 1 and h.connect_radius is not null and c.status=1 and h.type='Residential' and b.holdingNo is null
I would recommend changing the NOT IN to NOT EXISTS and adding an index:
WHERE . . . AND
NOT EXISTS (SELECT 1
FROM [db_land].[dbo].tbl_bill b
WHERE b.holdingNo = h.holdingNo AND
b.date_month >= DATEFROMPARTS(YEAR(#tdate), MONTH(#tdate), 1) AND
b.date_month < DATEADD(month, 1, DATEFROMPARTS(YEAR(#tdate), MONTH(#tdate), 1)) AND
(b.update_by IS NOT NULL OR b.ispay = 1
)
Then the index that you want is on tbl_bill(holdingNo, date_month, update_by, ispay).
Put your sub query into temp table :
DECLARE #tdate DATETIME = '2019-09-01 00:00:00.000'
SELECT holdingNo
into #TmpholdingNo
FROM [db_land].[dbo].tbl_bill
WHERE year(date_month) = YEAR(#tdate)
AND MONTH(date_month) = MONTH(#tdate)
AND ( update_by IS NOT NULL
OR ispay = 1 )
SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h
ON c.id = h.clid
WHERE h.status = 1
AND h.connect_radius IS NOT NULL
AND c.status = 1
AND h.type = 'Residential'
AND h.holdinNo NOT IN (SELECT holdingNo from #TmpholdingNo)
drop table #TmpholdingNo
Rather than using functions in your WHERE clause try calculating the start and end filter dates, using OPTION (RECOMPILE) can help SQL to use the actual values of your variables in your query plan. I would also change NOT IN to NOT EXISTS:
DECLARE #tdate DATETIME = '2019-09-01 00:00:00.000'
DECLARE #startDate DATE = DATEFROMPARTS(YEAR(#tdate), MONTH(#tdate), 1)
DECLARE #endDate DATE = DATEADD(day,1,EOMONTH(#tdate))
SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h
ON c.id = h.clid
WHERE h.status = 1
AND h.connect_radius IS NOT NULL
AND c.status = 1
AND h.type = 'Residential'
AND NOT EXISTS (SELECT holdingNo
FROM [db_land].[dbo].tbl_bill
WHERE holdingNo = h.holdinNo AND
date_month >= #startDate AND
date_month < #endDate AND
AND ( update_by IS NOT NULL
OR ispay = 1 ))
OPTION (RECOMPILE)
give a try try this:
select main.* from
(SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h
ON c.id = h.clid
WHERE h.status = 1
AND h.connect_radius IS NOT NULL
AND c.status = 1
AND h.type = 'Residential')main
left join
(select holdingNo from
(SELECT holdingNo, update_by, ispay
FROM [db_land].[dbo].tbl_bill
WHERE year(date_month) = YEAR(#tdate)
AND MONTH(date_month) = MONTH(#tdate))bill1
where update_by IS NOT NULL OR ispay = 1)bill2
on main.holdinNo = bill2.holdinNo
where bill2.holdinNo is null
put the filter list at variable,then them apply the filter
DECLARE #filter TABLE INSERT INTO #filter SELECT FROM [db_land].[dbo].tbl_bill
them apply the filter
DECLARE #tdate DATETIME = '2019-09-01 00:00:00.000'
SELECT c.id AS clid,
h.id AS hlid,
h.holdinNo,
c.cliendID,
c.clientName,
h.floor,
h.connect_radius
FROM [db_land].[dbo].tbl_client AS c
INNER JOIN [db_land].[dbo].tx_holding AS h ON c.id= h.clid
WHERE h.status=1
AND h.connect_radius IS NOT NULL
AND c.status=1
AND h.type='Residential'
AND h.holdinNo NOT IN (filter)

Convert nested Query to Join in SQL Server

I have a query
SELECT *
FROM Stops
WHERE CustomerID IN (SELECT ID FROM Customers WHERE Active = 1)
AND DriverID IS NOT NULL
AND TripID IN (SELECT ID
FROM Trips
WHERE ManagerID IN (SELECT ID FROM Users WHERE Active = 1)
AND AssignedToID IN (SELECT ID FROM Users WHERE Active = 1)
AND Modified > DATEADD(day, -60, GETDATE()))
I tried to convert to Join but I am stuck
SELECT *
FROM Stops S
JOIN Customers C ON C.ID = S.CustomerID
JOIN Trips T ON S.TripID = T.ID
WHERE C.ACTIVE = 1
AND S.DriverID IS NOT NULL
AND T.Modified > DATEADD(day, -60, GETDATE())
Using all joins, no nested queries
SELECT * FROM Stops A
INNER JOIN Customers B ON A.CustomerID = B.ID
INNER JOIN Trips C ON A.TripID = C.ID
INNER JOIN Users D ON C.ManagerID = D.ID
INNER JOIN Users E ON C.AssignedToID = E.ID
WHERE A.DriverID IS NOT NULL AND
B.Active = 1 AND
D.Active = 1 AND
E.Active = 1 AND
C.Modified > DATEADD(day, -60, GETDATE());
If you want unique data of stops you can also add "DISTINCT" to the select.
you can try like below subquery and join
SELECT S.* FROM Stops S
JOIN Customers C ON C.ID=S.CustomerID
join (SELECT ID FROM Trips where
ManagerID IN (SELECT ID FROM Users WHERE Active = 1) AND
AssignedToID IN (SELECT ID FROM Users WHERE Active = 1) AND
Modified > DATEADD(day, -60, GETDATE())
) t on S.TripID=t.ID
I'm trying your second code on my end until I came up on the below code. You might try
SELECT *
FROM Stops S
JOIN Customers C ON C.ID = S.CustomerID AND C.ACTIVE = 1
JOIN Trips T ON S.TripID = T.ID AND T.Modified > DATEADD(day, -60, GETDATE())
LEFT JOIN Users U ON T.ManagerID = U.ID AND T.AssignedToID = U.ID
WHERE S.DriverID IS NOT NULL
What I usually do is to draw squares as tables and link them based on the requirements.
Though, still not sure if my answer would work since I have no idea with what you are trying to achieve on your code aside from using JOIN.

MS SQL Order By To long execute

i have a problem with sql execution time with Order By.
The problem is if i am doing Order By, it is take a long time and i have a peak on my server.
If there any way to take a max values without order by
Example of Code with Order By:
SELECT DISTINCT TOP 3 s.title, s.imageUrl, count(sv.saleid) as mostViewPeriod14Days, s.guid
FROM dbo.Sales s
INNER JOIN dbo.KEY_BrandcategoryToSale b_key ON s.id = b_key.saleId
INNER JOIN dbo.SaleView sv ON s.id = sv.saleId
WHERE (sv.date <= GETDATE())
AND (sv.date >= GETDATE() - 14)
AND s.isActive = 1 AND s.isHotsale = 1
AND b_key.brandCategoryId = 28 AND s.id NOT IN (SELECT sv.saleId FROM dbo.SaleView sv WHERE sv.userId = 99114)
GROUP BY s.title, s.imageUrl, s.guid
ORDER BY mostViewPeriod14Days Desc
And what i what is work good but without order:
SELECT DISTINCT TOP 3 s.title, s.imageUrl, count(sv.saleid) as mostViewPeriod14Days, s.guid
FROM dbo.Sales s
INNER JOIN dbo.KEY_BrandcategoryToSale b_key ON s.id = b_key.saleId
INNER JOIN dbo.SaleView sv ON s.id = sv.saleId
WHERE (sv.date <= GETDATE())
AND (sv.date >= GETDATE() - 14)
AND s.isActive = 1 AND s.isHotsale = 1
AND b_key.brandCategoryId = 28 AND s.id NOT IN (SELECT sv.saleId FROM dbo.SaleView sv WHERE sv.userId = 99114)
GROUP BY s.title, s.imageUrl, s.guid
Try the query below and let me know if it helps. A few general points below
WHERE clauses that contain a calculated date are slower than those that don't.
If you can avoid it, never put a "sub-select" in a query. Change that to a left join and check for null records (it's way faster)
DECLARE #Today DATETIME;
DECLARE #TwoWeeksAgo DATETIME;
SET #Today = GETDATE();
SET #TwoWeeksAgo = DATEADD(DAY, -14, GETDATE());
SELECT TOP 3
s.title,
s.imageUrl,
count(sv.saleid) as mostViewPeriod14Days,
s.guid
FROM dbo.Sales s
INNER JOIN dbo.KEY_BrandcategoryToSale b_key ON s.id = b_key.saleId
INNER JOIN dbo.SaleView sv ON s.id = sv.saleId
LEFT JOIN dbo.SaleView sv2 on sv2.id = sv.id and sv2.userId = 99114
WHERE sv.Date BETWEEN #TwoWeeksAgo AND #Today
AND sv2.id IS NULL -- This is the check that handles your sub-select earlier
AND s.isActive = 1 AND s.isHotsale = 1
AND b_key.brandCategoryId = 28
GROUP BY s.title, s.imageUrl, s.guid
ORDER BY mostViewPeriod14Days Desc

Select inside CASE THEN

I need to select the project rate or shift rate that has the effective date less than today.
SELECT
CASE
WHEN ISNULL(s.rate,0) = 0
THEN SELECT TOP 1 pr.rate FROM ProjectRates pr WHERE (pr.projectID = p.ID) AND (pr.effectiveDate < GETDATE()) ORDER BY pr.effectiveDate DESC
--p.rate
ELSE SELECT TOP 1 sr.rate FROM ShiftRates sr WHERE (sr.shiftID = s.ID) AND (sr.effectiveDate < GETDATE()) ORDER BY pr.effectiveDate DESC
--s.rate
END AS rate
FROM Projects p
INNER JOIN Shifts s ON (p.ID = s.projectID)
WHERE (p.ID = #projectID)
Please note that this code snippet is part of a larger stored proc and thus it must be within a CASE statement.
Subqueries need parentheses:
SELECT (CASE WHEN ISNULL(s.rate, 0) = 0
THEN (SELECT TOP 1 pr.rate
FROM ProjectRates pr
WHERE (pr.projectID = p.ID) AND (pr.effectiveDate < GETDATE())
ORDER BY pr.effectiveDate DESC
)
ELSE (SELECT TOP 1 sr.rate
FROM ShiftRates sr
WHERE (sr.shiftID = s.ID) AND (sr.effectiveDate < GETDATE())
ORDER BY pr.effectiveDate DESC
) --s.rate
END) AS rate
FROM Projects p INNER JOIN
Shifts s
ON p.ID = s.projectID
WHERE p.ID = #projectID;