I need help regarding query optimization of the below query.
SELECT pr.todate , pr.descr, cmp.company_id
FROM employee AS emp
INNER JOIN company AS cmp ON emp.emp_comp_id = cmp.company_id
INNER JOIN profile AS pr ON emp.acca_id = pr.profile_id
INNER JOIN acondition ON as_id = as_ac_id
WHERE as_closed = 0
AND (pr.ac_act_id = 20)
AND (pr.todate = (SELECT MIN(todate) AS Expr1
FROM profile pro
INNER JOIN employee empl ON empl.acca_id = pro.profile_id
JOIN acondition ON as_id = as_ac_id
WHERE (pro.ac_act_id = 20
AND empl.emp_comp_id = cmp.company_id)
AND as_closed = 0))
Since there are duplicate joins in the main query and sub query, is there any way to remove those joins in the subquery?
Since, as you clarified, your sub-query is almost identical to your main query you might be able to use the window function RANK as a filter condition. RANK assigns the same number to ties, meaning if multiple records per company match you will get them all e.g.
SELECT todate, descr, company_id
FROM (
SELECT pr.todate, pr.descr, cmp.company_id
, RANK() OVER (PARTITION BY cmp.company_id ORDER BY pr.todate ASC) RankNumber
FROM employee AS emp
INNER JOIN company AS cmp ON emp.emp_comp_id = cmp.company_id
INNER JOIN profile AS pr ON emp.acca_id = pr.profile_id
INNER JOIN acondition ON as_id = as_ac_id
WHERE as_closed = 0 AND pr.ac_act_id = 20
) X
where RankNumber = 1;
Does this work for you?
SELECT ca.todate , pr.descr, cmp.company_id
FROM employee AS emp
INNER JOIN company AS cmp ON emp.emp_comp_id = cmp.company_id
CROSS APPLY (
SELECT TOP(1) pr.todate
FROM profile pr
INNER JOIN acondition ON as_id = as_ac_id
WHERE emp.acca_id = pr.profile_id AND (pr.ac_act_id = 20) AND as_closed = 0
ORDER BY pr.todate ASC
) AS ca
Related
This SQL query needs to be done in ACCESS.
I am trying to do a subquery on the total sales, but I want to link the sale to the province AND to product. The below query will work with one or the other: (po.product_name = allp.all_products) AND (p.province = allp.all_province); -- but it will no take both.
I will be including every month into this query, once I can figure out the subquery on with two criteria.
Select
p.province as [Province],
po.product_name as [Product],
all_price
FROM
(purchase_order po
INNER JOIN person p
on p.person_id = po.person_id)
left join
(
select
po1.product_name AS [all_products],
sum(pp1.price) AS [all_price],
p1.province AS [all_province]
from (purchase_order po1
INNER JOIN product pp1
on po1.product_name = pp1.product_name)
INNER JOIN person p1
on po1.person_id = p1.person_id
group by po1.product_name, pp1.price, p1.province
)
as allp
on (po.product_name = allp.all_products) AND (p.province = allp.all_province);
Make the first select sql into a table by giving it an alias and join table 1 to table 2. I don't have your table structure or data to test it but I think this will lead you down the right path:
select table1.*, table2.*
from
(Select
p.province as [Province],
po.product_name as [Product]
--removed this ,all_price
FROM
(purchase_order po
INNER JOIN person p
on p.person_id = po.person_id) table1
left join
(
select
po1.product_name AS [all_products],
sum(pp1.price) AS [all_price],
p1.province AS [all_province]
from (purchase_order po1
INNER JOIN product pp1
on po1.product_name = pp1.product_name)
INNER JOIN person p1
on po1.person_id = p1.person_id
group by po1.product_name, pp1.price, p1.province --check your group by, I dont think you want pp1.price here if you want to aggregate
) as table2 --changed from allp
on (table1.product = table2.all_products) AND (table1.province = table2.all_province);
I am trying to filter cg_group names (please check the query) and group (using: GROUP BY) the results according to last updated opportunity (using: ORDER BY opportunities.date_modified DESC).
When I used query without use group by it returns the following results:
SELECT cg_groups.name
FROM cg_groups
JOIN cg_groups_cstm ON cg_groups_cstm.id_c = cg_groups.id
JOIN accounts_cstm ON cg_groups.name = accounts_cstm.client_group_c
JOIN accounts ON accounts.id = accounts_cstm.id_c
JOIN accounts_opportunities ON accounts.id = accounts_opportunities.account_id
JOIN opportunities ON accounts_opportunities.opportunity_id = opportunities.id
WHERE cg_groups.deleted='0' AND cg_groups_cstm.status_c='1' AND opportunities.deleted='0'
ORDER BY opportunities.date_modified DESC
Results:
ABC Group
ABC Group
CBC Group
ABC Group
XYZ Group
But I want to group this to following order:
ABC Group
CBC Group
XYZ Group
To do that I added GROUP BY cg_groups.name
SELECT cg_groups.name
FROM cg_groups
JOIN cg_groups_cstm ON cg_groups_cstm.id_c = cg_groups.id
JOIN accounts_cstm ON cg_groups.name = accounts_cstm.client_group_c
JOIN accounts ON accounts.id = accounts_cstm.id_c
JOIN accounts_opportunities ON accounts.id = accounts_opportunities.account_id
JOIN opportunities ON accounts_opportunities.opportunity_id = opportunities.id
WHERE cg_groups.deleted='0' AND cg_groups_cstm.status_c='1' AND opportunities.deleted='0'
GROUP BY cg_groups.name
ORDER BY opportunities.date_modified DESC
But now I get this error:
Msg 8127, Level 16, State 1, Line 10
Column "opportunities.date_modified" is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause.
Someone please help me to solve this issue, thank you.
Use ROW_NUMBER to find the most recently updated record for each group:
WITH cte AS (
SELECT cg_groups.name, o.date_modified,
ROW_NUMBER() OVER (PARTITION BY o.date_modified DESC) rn
FROM cg_groups cg
INNER JOIN cg_groups_cstm cgc
ON cgc.id_c = cg.id
INNER JOIN accounts_cstm ac
ON cg.name = ac.client_group_c
INNER JOIN accounts a
ON a.id = ac.id_c
INNER JOIN accounts_opportunities ao
ON a.id = ao.account_id
INNER JOIN opportunities o
ON ao.opportunity_id = o.id
WHERE cg.deleted = '0' AND cgc.status_c = '1' AND o.deleted = '0'
)
SELECT name
FROM cte
WHERE rn = 1
ORDER BY date_modified DESC;
Note that this may not be exactly what you want. This answer returns a single record per name group which is the most recently updated for that group. It then orders all results descending, but maybe you want ascending.
put opportunities.date_modified in selection and group by then you can use that in order by
SELECT opportunities.date_modified,cg_groups.name
FROM cg_groups
JOIN cg_groups_cstm ON cg_groups_cstm.id_c = cg_groups.id
JOIN accounts_cstm ON cg_groups.name = accounts_cstm.client_group_c
JOIN accounts ON accounts.id = accounts_cstm.id_c
JOIN accounts_opportunities ON accounts.id = accounts_opportunities.account_id
JOIN opportunities ON accounts_opportunities.opportunity_id = opportunities.id
WHERE cg_groups.deleted='0' AND cg_groups_cstm.status_c='1' AND opportunities.deleted='0'
GROUP BY cg_groups.name,opportunities.date_modified
ORDER BY opportunities.date_modified DESC
but for your result you can try like below just use distinct
SELECT distinct cg_groups.name
FROM cg_groups
JOIN cg_groups_cstm ON cg_groups_cstm.id_c = cg_groups.id
JOIN accounts_cstm ON cg_groups.name = accounts_cstm.client_group_c
JOIN accounts ON accounts.id = accounts_cstm.id_c
JOIN accounts_opportunities ON accounts.id = accounts_opportunities.account_id
JOIN opportunities ON accounts_opportunities.opportunity_id = opportunities.id
WHERE cg_groups.deleted='0' AND cg_groups_cstm.status_c='1' AND opportunities.deleted='0'
order by cg_groups.name
no group by need as you have not used any aggregate function
how about just adding distinct right after your SELECT statement .
Select distinct ... from ...
I have the following SQL Server code to get information from a combination of 4 tables.
I would like to modify it to only retrieve the latest 3 orders (pmpOrderDate) by supplier (pmpSupplierOrganizationID).
SELECT
PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID, O.cmoName
FROM
PurchaseOrders PO
INNER JOIN
PurchaseOrderLines POL ON PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID
INNER JOIN
Organizations O ON PO.pmpSupplierOrganizationID = O.cmoOrganizationID
INNER JOIN
Parts P ON POL.pmlPartID = P.impPartID
WHERE
P.impPartClassID LIKE 'PUMP%'
Can you please help?
EDIT:
I wasn't fully clear on my actual requirements. To clarify further, what I need in the end is to display the latest 3 unique Purchase Orders by Supplier ID based on at least one of the PartClassID for the PartID in the PurchaseOrderLines to have criteria of beginning with string 'PUMP'
Use a ROW_NUMBER to partition by pmpSupplierOrganizationID and order by pmpOrderDate.
with cteTopOrders AS (
SELECT PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID, O.cmoName,
ROW_NUMBER() OVER(PARTITION BY pmpSupplierOrganizationID ORDER BY pmpOrderDate DESC) AS RowNum
FROM PurchaseOrders PO
Inner Join PurchaseOrderLines POL ON PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID
Inner Join Organizations O On PO.pmpSupplierOrganizationID = O.cmoOrganizationID
Inner Join Parts P ON POL.pmlPartID = P.impPartID
WHERE P.impPartClassID Like 'PUMP%'
)
SELECT pmpPurchaseOrderID, pmpOrderDate, pmpSupplierOrganizationID, cmoName
FROM cteTopOrders
WHERE RowNum <= 3;
I'm a fan of lateral joins for this . . . cross apply:
select p.*, O.cmoName
from Organizations O cross apply
(select top (3) PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID
from PurchaseOrders PO join
PurchaseOrderLines POL
on PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID join
Parts P
on POL.pmlPartID = P.impPartID
where PO.pmpSupplierOrganizationID = O.cmoOrganizationID and
P.impPartClassID Like 'PUMP%'
order by PO.pmpOrderDate desc
) p
You need a nested row_number to get the three rows per supplier and another OLAP-function on top of it:
with OrderRowNum as
(
SELECT PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID, O.cmoName, P.impPartClassID,
row_number()
over (partition by PO.pmpSupplierOrganizationID
order by pmpOrderDate desc) as rn
FROM PurchaseOrders PO
Inner Join PurchaseOrderLines POL ON PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID
Inner Join Organizations O On PO.pmpSupplierOrganizationID = O.cmoOrganizationID
Inner Join Parts P ON POL.pmlPartID = P.impPartID
)
, CheckPUMP as
(
select *,
-- check if at least one of the three rows contains PUMP
max(case when impPartClassID Like 'PUMP%' then 1 else 0 end)
over (partition by PO.pmpSupplierOrganizationID) as PUMPflag
from OrderRowNum
where rn <= 3 -- get the last three rows per supplier
)
select *
from CheckPUMP
where flag = 1
I have my initial statement which is :
SELECT TEAM.ID PKEY_SRC_OBJECT,
TEAM.MODF_DAT UPDATE_DATE,
TEAM.MODF_USR UPDATED_BY,
PERSO.FIRST_NAM FISRT_NAME
FROM TEAM
LEFT OUTER JOIN PERSO ON (TEAM.ID=PERSO.TEAM_ID)
I want to calculate some "flags" and return them in my initial statement.
There are 3 flags which can be calculated like this :
1) Flag ISMASTER:
SELECT Count(*)
FROM TEAM_TEAM_REL A, TEAM B
WHERE B.PARTY_PTY_ID = A.RLTD_TEAM_ID
AND CODE = 'Double';
2) Flag ISAGENT:
SELECT Count(*)
FROM TEAM_ROL_REL A, TEAM B
WHERE B.PARTY_PTY_ID = A.TEAM_ID;
3) Flag NUMPACTS:
SELECT Count(*)
FROM TEAM_ROL_REL A,
TEAM_ROL_POL_REL B,
PERSO_POL_STA_REL C,
TEAM D
WHERE A.ROL_CD IN ('1','2')
AND A.T_ROL_REL_ID = B.P_ROL_REL_ID
AND B.P_POL_ID = C.P_POL_ID
AND C.STA_CD = 'A'
AND D.PARTY_PTY_ID = A.TEAM_ID;
To try to achieve this, I've updated my initial statement like this :
WITH ABC AS (
SELECT TEAM.ID PKEY_SRC_OBJECT,
TEAM.MODF_DAT UPDATE_DATE,
TEAM.MODF_USR UPDATED_BY,
PERSO.FIRST_NAM FISRT_NAME
FROM TEAM
LEFT OUTER JOIN PERSO ON (TEAM.ID=PERSO.TEAM_ID)
)
SELECT ABC.*, MAST.ISMASTER, AGENT.ISAGENT, PACTS.NUMPACTS FROM ABC
LEFT OUTER JOIN (
select
RLTD_TEAM_ID,
Count(RLTD_TEAM_ID) OVER (PARTITION BY RLTD_TEAM_ID) as ISMASTER
FROM TEAM_TEAM_REL
WHERE CODE = 'Double'
) MAST
ON ABC.PKEY_SRC_OBJECT = MAST.RLTD_TEAM_ID
LEFT OUTER JOIN (
select
TEAM_ID,
Count(TEAM_ID) OVER (PARTITION BY TEAM_ID) as ISAGENT
FROM TEAM_ROL_REL
) AGENT
ON ABC.PKEY_SRC_OBJECT = AGENT.TEAM_ID
LEFT OUTER JOIN (
select
TEAM_ID,
Count(TEAM_ID) OVER (PARTITION BY TEAM_ID) as NUMPACTS
FROM TEAM_ROL_REL, TEAM_ROL_POL_REL, PERSO_POL_STA_REL
WHERE TEAM_ROL_REL.ROL_CD IN ('1','2')
AND TEAM_ROL_REL.T_ROL_REL_ID = TEAM_ROL_POL_REL.P_ROL_REL_ID
AND TEAM_ROL_POL_REL.P_POL_ID = PERSO_POL_STA_REL.P_POL_ID
AND PERSO_POL_STA_REL.STA_CD = 'A'
) PACTS
ON ABC.PKEY_SRC_OBJECT = PACTS.TEAM_ID;
For the two first flags (ISMASTER and ISAGENT) I get the result in less than 1min, but for the last flag (NUMPACTS) it runs few minutes without provide any result.
I think my statement is too heavy, maybe I should do it in a totally different way.
I think you have perhaps over complicated things.
You could do this (assuming I have understood your requirements correctly) like so:
WITH ttr AS (SELECT rltd_team_id,
COUNT(*) is_master
FROM team_team_rel
AND CODE = 'Double'
GROUP BY rltd_team_id),
trr AS (SELECT team_id,
COUNT(*) is_agent
FROM team_rol_rel
GROUP BY team_id)
pacts AS (SELECT trr1.team_id,
COUNT(*) num_pacts
FROM team_rol_rel trr1
INNER JOIN team_rol_pol_rel trpr ON (trr1.t_rol_rel_id = trpr.p_rol_rel_id)
INNER JOIN perso_pol_sta_rel ppsr ON (trpr.p_pol_id = ppsr.p_pol_id
WHERE trr1.rol_cd IN ('1', '2')
AND ppsr.st_cd = 'A'
GROUP BY trr1.team_id)
SELECT t.id pkey_src_object,
t.modf_dat update_date,
t.modf_usr updated_by,
p.first_nam first_name,
ttr.is_master,
trr.is_agent,
pacts.num_pacts
FROM team t
LEFT OUTER JOIN perso p ON t.id = p.team_id
LEFT OUTER JOIN ttr ON t.party_pty_id = ttr.rltd_team_id
LEFT OUTER JOIN trr ON t.party_pty_id = trr.team_id
LEFT OUTER JOIN pacts ON t.pkey_src_object = pacts.team_id;
N.B. untested, since you didn't provide any test data.
I need to sort the results of a query after insert a value to a variable.
I am trying to sort according to 'RowId' but its not valid in my case.
Below is my query, how can I make it work?
Thanks.
SELECT TOP 1 #NumOfProducts = ROW_NUMBER() OVER(ORDER BY Products.Id) AS RowId
FROM Cities INNER JOIN
CitiesInLanguages ON Cities.Id = CitiesInLanguages.CityId INNER JOIN
ShopsInCities ON Cities.Id = ShopsInCities.CityId INNER JOIN
Categories INNER JOIN
ProductstInCategories ON Categories.Id = ProductstInCategories.CategoryId INNER JOIN
Products ON ProductstInCategories.ProductId = Products.Id INNER JOIN
ProductsInProdutGroup ON Products.Id = ProductsInProdutGroup.ProductId INNER JOIN
ProductsGroups ON ProductsInProdutGroup.ProductGroupId = ProductsGroups.Id INNER JOIN
ShopsInProductsGroup ON ProductsGroups.Id = ShopsInProductsGroup.ProductGroupId INNER JOIN
aspnet_Users ON ShopsInProductsGroup.ShopId = aspnet_Users.UserId ON ShopsInCities.ShopId = aspnet_Users.UserId INNER JOIN
ProductsNamesInLanguages ON Products.Id = ProductsNamesInLanguages.ProductId INNER JOIN
UsersInfo ON aspnet_Users.UserId = UsersInfo.UserId INNER JOIN
ProductOptions ON Products.Id = ProductOptions.ProductId INNER JOIN
ProductOptionsInLanguages ON ProductOptions.Id = ProductOptionsInLanguages.ProductOptionId INNER JOIN
ProductFiles ON Products.Id = ProductFiles.ProductId INNER JOIN
ProductsInOccasions ON Products.Id = ProductsInOccasions.ProductId INNER JOIN
Occasions ON ProductsInOccasions.OccasionId = Occasions.Id INNER JOIN
OccasionsInLanguages ON Occasions.Id = OccasionsInLanguages.OccasionId
WHERE (Products.IsAddition = 0) AND (Categories.IsEnable = 1) AND (Products.IsEnable = 1) AND (ProductsGroups.IsEnable = 1) AND (Cities.IsEnable = 1) AND
(ShopsInProductsGroup.IsEnable = 1) AND (CitiesInLanguages.CityName = #CityName) AND (ProductsNamesInLanguages.LanguageId = #languageId) AND
(Categories.Id = #CategoryId) AND (ProductOptions.IsEnable = 1) AND (ProductFiles.IsEnable = 1)
group by Products.Id, ProductsNamesInLanguages.ProductName, UsersInfo.Name
Order By RowId
With edit try this:
SELECT TOP 1 #NumOfProducts = ROW_NUMBER() OVER(ORDER BY Products.Id),
ROW_NUMBER() OVER(ORDER BY Products.Id) AS RowId
or try
ORDER BY ROW_NUMBER() OVER(ORDER BY Products.Id)
I'd have to test but I thik both will work.
The problem is that rowid is not in any of the group by items.
You could order by Products.id. If rowid is going to be the same for each one you could order by max(rowid) or min(rowid) or add rowid to the group by statement.
Are you trying to find the ID of the most recently inserted row? You want
SELECT Scope_Identity()
Edit
*I am trying to get the max row id of ROW_NUMBER()*
Wrap your query in
SELECT #NumOfProducts = Max(RowID) FROM
( [your query here] ) v
Alternately, a SELECT COUNT... query may provide the answer