下午好。我将把存储过程发布到它的整个荣耀中。随意把它撕成碎片。作者不介意。
DECLARE @itemTypeID INT
SELECT @itemTypeID=ItemTypeID FROM dbo.ItemTypes WHERE ItemTypeName = 'Advert'
BEGIN
SELECT a.Active,
a.ParentClass,
a.Classification,
a.Variant,
FV."Full Views",
PV."Print Views",
EE."Email Enquiries",
a.ItemRef,
a.SiteID
FROM
(
SELECT DISTINCT i.ItemID,
i.ItemRef,
i.SiteID,
i.ParentClass,
i.Classification,
i.Summary AS "Variant",
i.Active
FROM Items i
JOIN Actions a
ON a.ItemID = i.ItemID
JOIN ActionTypes at
ON a.ActionTypeID = at.ActionTypeID
WHERE i.ItemTypeID = 1
AND a.DateAndTime BETWEEN @startDate AND @endDate
AND at.ActionTypeName IN ('Full view', 'Print view', 'Email enquiry')
AND ((@siteID = -1) OR (i.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
) a LEFT JOIN
(
SELECT i.ItemID,
COUNT(*) AS "Full Views"
FROM CustomerSites cs JOIN Items i
ON cs.SiteID = i.SiteID
JOIN Actions a
ON a.ItemID = i.ItemID
JOIN ActionTypes at
ON a.ActionTypeID = at.ActionTypeID
JOIN Sites s
ON cs.SiteID = s.SiteID
WHERE a.DateAndTime BETWEEN @startDate AND @endDate
AND i.ItemTypeID = @itemTypeID
AND at.ActionTypeName = 'Full view'
AND ((@customerID IS NULL) OR (cs.CustomerID = @customerID))
AND ((@siteID = -1) OR (cs.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
GROUP BY
i.ItemID
) FV
ON a.ItemID = FV.ItemID
LEFT JOIN
(
SELECT i.ItemID,
COUNT(*) AS "Print Views"
FROM CustomerSites cs JOIN Items i
ON cs.SiteID = i.SiteID
JOIN Actions a
ON a.ItemID = i.ItemID
JOIN ActionTypes at
ON a.ActionTypeID = at.ActionTypeID
JOIN Sites s
ON cs.SiteID = s.SiteID
WHERE a.DateAndTime BETWEEN @startDate AND @endDate
AND i.ItemTypeID = @itemTypeID
AND at.ActionTypeName = 'Print view'
AND ((@customerID IS NULL) OR (cs.CustomerID = @customerID))
AND ((@siteID = -1) OR (cs.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
GROUP BY
i.ItemID
) PV
ON a.ItemID = PV.ItemID
LEFT JOIN
(
SELECT i.ItemID,
COUNT(*) AS "Email Enquiries"
FROM CustomerSites cs JOIN Items i
ON cs.SiteID = i.SiteID
JOIN Actions a
ON a.ItemID = i.ItemID
JOIN ActionTypes at
ON a.ActionTypeID = at.ActionTypeID
JOIN Sites s
ON cs.SiteID = s.SiteID
WHERE a.DateAndTime BETWEEN @startDate AND @endDate
AND i.ItemTypeID = @itemTypeID
AND at.ActionTypeName = 'Email enquiry'
AND ((@customerID IS NULL) OR (cs.CustomerID = @customerID))
AND ((@siteID = -1) OR (cs.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
GROUP BY
i.ItemID
) EE
ON a.ItemID = EE.ItemID
UNION
SELECT '0','','','','','','','',''
现在最终所有这一切都会返回一些记录以及针对它们发生特定操作的次数。
一个小子集看起来像。
项目描述查看已打印的电子邮件
Item1 Desc1 12 NULL 1
Item2 Desc2 NULL NULL 3
Item3 Desc3 5 6 2
希望你能看到发生了什么。
我想要针对特定网站的特定客户针对特定日期范围针对他们采取操作的项目列表,并且该查询应该可以在父类和分类上过滤。尼斯
第一个选择返回属于选择条件的所有不同项目。
其他3个查询都只是针对每个项目返回1种操作类型的计数。即使针对少量数据,查询也很慢。这永远不会生效,只是不起作用。
希望您能看到“作者”方式的错误并纠正他/她。
答案 0 :(得分:4)
这是我的格式化样式的原始查询:
SELECT
a.Active
,a.ParentClass
,a.Classification
,a.Variant
,FV."Full Views"
,PV."Print Views"
,EE."Email Enquiries"
,a.ItemRef
,a.SiteID
FROM (SELECT DISTINCT
i.ItemID,
,i.ItemRef
,i.SiteID
,i.ParentClass
,i.Classification
,i.Summary AS "Variant"
,i.Active
FROM Items i
JOIN Actions a ON a.ItemID = i.ItemID
JOIN ActionTypes at ON a.ActionTypeID = at.ActionTypeID
WHERE i.ItemTypeID = 1
AND a.DateAndTime BETWEEN @startDate AND @endDate
AND at.ActionTypeName IN ('Full view', 'Print view', 'Email enquiry')
AND ((@siteID = -1) OR (i.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
) a
LEFT JOIN (SELECT
i.ItemID
,COUNT(*) AS "Full Views"
FROM CustomerSites cs
JOIN Items i ON cs.SiteID = i.SiteID
JOIN Actions a ON a.ItemID = i.ItemID
JOIN ActionTypes at ON a.ActionTypeID = at.ActionTypeID
JOIN Sites s ON cs.SiteID = s.SiteID
WHERE a.DateAndTime BETWEEN @startDate AND @endDate
AND i.ItemTypeID = @itemTypeID
AND at.ActionTypeName = 'Full view'
AND ((@customerID IS NULL) OR (cs.CustomerID = @customerID))
AND ((@siteID = -1) OR (cs.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
GROUP BY i.ItemID
) FV ON a.ItemID = FV.ItemID
LEFT JOIN (SELECT
i.ItemID
,COUNT(*) AS "Print Views"
FROM CustomerSites cs
JOIN Items i ON cs.SiteID = i.SiteID
JOIN Actions a ON a.ItemID = i.ItemID
JOIN ActionTypes at ON a.ActionTypeID = at.ActionTypeID
JOIN Sites s ON cs.SiteID = s.SiteID
WHERE a.DateAndTime BETWEEN @startDate AND @endDate
AND i.ItemTypeID = @itemTypeID
AND at.ActionTypeName = 'Print view'
AND ((@customerID IS NULL) OR (cs.CustomerID = @customerID))
AND ((@siteID = -1) OR (cs.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
GROUP BY i.ItemID
) PV ON a.ItemID = PV.ItemID
LEFT JOIN (SELECT
i.ItemID
,COUNT(*) AS "Email Enquiries"
FROM CustomerSites cs
JOIN Items i ON cs.SiteID = i.SiteID
JOIN Actions a ON a.ItemID = i.ItemID
JOIN ActionTypes at ON a.ActionTypeID = at.ActionTypeID
JOIN Sites s ON cs.SiteID = s.SiteID
WHERE a.DateAndTime BETWEEN @startDate AND @endDate
AND i.ItemTypeID = @itemTypeID
AND at.ActionTypeName = 'Email enquiry'
AND ((@customerID IS NULL) OR (cs.CustomerID = @customerID))
AND ((@siteID = -1) OR (cs.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
GROUP BY i.ItemID
) EE ON a.ItemID = EE.ItemID
UNION
SELECT '0','','','','','','','',''
这应该有所帮助:
;WITH CustomerSitesCounts AS
(
SELECT
at.ActionTypeName
,i.ItemID
,COUNT(*) AS "Print Views"
FROM CustomerSites cs
JOIN Items i ON cs.SiteID = i.SiteID
JOIN Actions a ON a.ItemID = i.ItemID
JOIN ActionTypes at ON a.ActionTypeID = at.ActionTypeID
JOIN Sites s ON cs.SiteID = s.SiteID
WHERE a.DateAndTime BETWEEN @startDate AND @endDate
AND i.ItemTypeID = @itemTypeID
AND at.ActionTypeName IN ( 'Print view','Full view','Email enquiry')
AND ((@customerID IS NULL) OR (cs.CustomerID = @customerID))
AND ((@siteID = -1) OR (cs.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
GROUP BY at.ActionTypeName,i.ItemID
)
SELECT
a.Active
,a.ParentClass
,a.Classification
,a.Variant
,FV."Full Views"
,PV."Print Views"
,EE."Email Enquiries"
,a.ItemRef
,a.SiteID
FROM (SELECT DISTINCT
i.ItemID,
,i.ItemRef
,i.SiteID
,i.ParentClass
,i.Classification
,i.Summary AS "Variant"
,i.Active
FROM Items i
JOIN Actions a ON a.ItemID = i.ItemID
JOIN ActionTypes at ON a.ActionTypeID = at.ActionTypeID
WHERE i.ItemTypeID = 1
AND a.DateAndTime BETWEEN @startDate AND @endDate
AND at.ActionTypeName IN ('Full view', 'Print view', 'Email enquiry')
AND ((@siteID = -1) OR (i.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
) a
LEFT JOIN CustomerSitesCounts FV ON a.ItemID = FV.ItemID AND FV.ActionTypeName='Full view'
LEFT JOIN CustomerSitesCounts PV ON a.ItemID = PV.ItemID AND PV.ActionTypeName='Print view'
LEFT JOIN CustomerSitesCounts EE ON a.ItemID = EE.ItemID AND EE.ActionTypeName='Email enquiry'
UNION
SELECT '0','','','','','','','',''
答案 1 :(得分:3)
问题:
这应该是最快的解决方案:
DECLARE @sql AS VARCHAR(MAX)
SELECT @sql = '
;WITH cteCommon as (
SELECT
i.ItemID,
,i.ItemRef
,i.SiteID
,i.ParentClass
,i.Classification
,i.Summary
,i.Active
,at.ActionTypeName
FROM Items i
JOIN Actions a ON a.ItemID = i.ItemID
JOIN ActionTypes at ON a.ActionTypeID = at.ActionTypeID
WHERE at.ActionTypeName IN (''Full view'', ''Print view'', ''Email enquiry'')
--NOTE: if you max-out this date range, then you mant want to exclude it also, RBarryYoung
AND a.DateAndTime BETWEEN @startDate AND @endDate
'
+ CASE @siteid WHEN -1 THEN '' ELSE 'AND (i.SiteID = @siteID)
' END
+ CASE @parentClass WHEN '%' THEN '' ELSE 'AND (i.ParentClass = @parentClass)
' END
+ CASE @class WHEN '%' THEN '' ELSE 'AND (i.classification = @class)
' END
+ '
)
, cteA as (
SELECT DISTINCT
i.ItemID,
,i.ItemRef
,i.SiteID
,i.ParentClass
,i.Classification
,i.Summary AS "Variant"
,i.Active
FROM cteA as i
WHERE i.ItemTypeID = 1
)
, cteCountViews AS (
SELECT
i.ItemID
,i.ActionType
,COUNT(*) AS "ViewCount"
FROM cteCommon i
JOIN CustomerSites cs ON cs.SiteID = i.SiteID
JOIN Sites s ON cs.SiteID = s.SiteID
WHERE i.ItemTypeID = @itemTypeID
'
+ CASE WHEN @customerid IS NULL THEN '' ELSE '(cs.CustomerID = @customerID)' END
+ '
GROUP BY i.ItemID
,i.ActionType
)
SELECT
a.Active
,a.ParentClass
,a.Classification
,a.Variant
,FV."Full Views"
,PV."Print Views"
,EE."Email Enquiries"
,a.ItemRef
,a.SiteID
FROM cteA AS a
LEFT JOIN (
SELECT i.ItemID, ViewCount AS "Full Views"
FROM cteCountViews i
WHERE i.ActionTypeName = ''Full view''
) FV ON a.ItemID = FV.ItemID
LEFT JOIN (
SELECT i.ItemID, ViewCount AS "Print Views"
FROM cteCountViews i
WHERE i.ActionTypeName = ''Print view''
) PV ON a.ItemID = PV.ItemID
LEFT JOIN (
SELECT i.ItemID, ViewCount AS "Email Enquiries"
FROM cteCountViews i
WHERE i.ActionTypeName = ''Email enquiry''
) EE ON a.ItemID = EE.ItemID
UNION ALL
SELECT ''0'','''','''','''','''','''','''','''',''''
'
EXEC sp_ExecuteSQL @sql
,'@startdate DATETIME,@enddate DATETIME,@siteid INT,@parentclass VARCHAR(MAX),@class VARCHAR(MAX),@itemtypeid INT,@customerid INT'
, @startdate, @enddate, @siteid, @parentclass, @class, @itemtypeid, @customerid
注意:在带有JOIN的某些(类,站点等)上使用通配符可能会导致源行和大量结果集的交叉乘法。
答案 2 :(得分:1)
首先,您可以避免使用3个绝对相同的子查询副本购买具有通用的子查询,并使用WITH语句以便您可以重复使用它。
然后,为什么在不需要时进行子选择。
然后再删除一些你不需要的连接(以及DISTINCT)。
你从这些方面得到了一些东西(当然没有经过测试):
DECLARE @itemTypeID INT
SELECT @itemTypeID=ItemTypeID FROM dbo.ItemTypes WHERE ItemTypeName = 'Advert'
BEGIN
WITH ItemTypeSummary
AS (SELECT i.ItemID,
at.ActionTypeName,
COUNT(*) AS CNT
FROM Items i
JOIN Actions a
ON a.ItemID = i.ItemID
JOIN ActionTypes at
ON a.ActionTypeID = at.ActionTypeID
AND at.ActionTypeName IN ('Full view', 'Print view', 'Email enquiry')
WHERE a.DateAndTime BETWEEN @startDate AND @endDate
--// not sure you need those below as they are all part of Items filter anyways in the main query
/*
AND i.ItemTypeID = @itemTypeID
AND ((@customerID IS NULL) OR (cs.CustomerID = @customerID))
AND ((@siteID = -1) OR (cs.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
*/
GROUP BY i.ItemID,
at.ActionTypeName
)
SELECT DISTINCT i.ItemID,
i.ItemRef,
i.SiteID,
i.ParentClass,
i.Classification,
i.Summary AS "Variant",
i.Active,
FV.CNT AS "Full views",
PV.CNT AS "Print views",
EE.CNT AS "Email enquiries"
FROM Items i
JOIN CustomerSites cs
ON cs.SiteID = i.SiteID
LEFT JOIN ItemTypeSummary FV
ON i.ItemID = FV.ItemID
AND FV.ActionTypeName = 'Full view'
LEFT JOIN ItemTypeSummary PV
ON i.ItemID = PV.ItemID
AND PV.ActionTypeName = 'Print view'
LEFT JOIN ItemTypeSummary EE
ON i.ItemID = EE.ItemID
AND EE.ActionTypeName = 'Email enquiry'
WHERE i.ItemTypeID = @itemTypeID
AND ((@customerID IS NULL) OR (cs.CustomerID = @customerID))
AND ((@siteID = -1) OR (i.SiteID = @siteID))
AND ((@parentClass = '%') OR (i.ParentClass = @parentClass))
AND ((@class = '%') OR (i.classification = @class))
END
另外请记住,如果可以避免使用这些OR语句,那么使用过滤器 ALL或特定项的技巧并不是很酷,因为SQLServer将无法生成最佳执行计划。
答案 3 :(得分:1)
另一种选择是设置表变量或临时#Table来保存结果。在ItemID上添加唯一约束。
将子系统拆分为单独的步骤。首先将要计算的记录INSERT到此表中。对每种视图类型的数据运行单独的UPDATE - 更新打印视图计数,更新全视图计数,更新电子邮件查询计数。然后返回结果。如有必要,将OR条件拆分为单独的查询。
这种方法会多次运行您的数据,但它会避免LEFT JOIN和未编入索引的子查询。
在我们的应用中,拥有多个步骤似乎比一个非常复杂的查询表现更好。您的结果可能会有所不同。
答案 4 :(得分:1)
改写为:
WITH base AS (
SELECT i.ItemID,
i.ItemRef,
i.SiteID,
i.ParentClass,
i.Classification,
i.Summary,
i.Active,
i.ItemTypeID,
at.ActionTypeName
FROM ITEMS i
JOIN ACTIONS a ON a.ItemID = i.ItemID
JOIN ACTIONTYPES at ON at.ActionTypeID = a.ActionTypeID
WHERE a.DateAndTime BETWEEN @startDate AND @endDate
AND (@siteID = -1 OR i.SiteID = @siteID)
AND (@parentClass = '%' OR i.ParentClass = @parentClass)
AND (@class = '%' OR i.classification = @class)),
items AS (
SELECT b.ItemID,
b.ItemRef,
b.SiteID,
b.ParentClass,
b.Classification,
b.Summary AS "Variant",
b.Active
FROM base b
WHERE b.itemtypeid = 1
AND b.actiontypename IN ('Full view', 'Print view', 'Email enquiry')
GROUP BY i.ItemID, i.ItemRef, i.SiteID, i.ParentClass, i.Classification, i.Summary, i.Active),
full_views AS (
SELECT b.ItemID,
COUNT(*) AS num_full_Views
FROM base b
JOIN CUSTOMERSITES cs ON cs.siteid = b.siteid
JOIN SITES s ON s.siteid = b.siteid
WHERE b.itemtypeid = @itemTypeID
AND b.ActionTypeName = 'Full view'
AND (@customerID IS NULL OR cs.CustomerID = @customerID)
GROUP BY b.itemid),
print_views AS (
SELECT b.ItemID,
COUNT(*) AS num_print_views
FROM base b
JOIN CUSTOMERSITES cs ON cs.siteid = b.siteid
JOIN SITES s ON s.siteid = b.siteid
WHERE b.itemtypeid = @itemTypeID
AND b.ActionTypeName = 'Print view'
AND (@customerID IS NULL OR cs.CustomerID = @customerID)
GROUP BY b.itemid),
email_queries AS (
SELECT b.ItemID,
COUNT(*) AS num_email_enquiries
FROM base b
JOIN CUSTOMERSITES cs ON cs.siteid = b.siteid
JOIN SITES s ON s.siteid = b.siteid
WHERE b.itemtypeid = @itemTypeID
AND b.ActionTypeName = 'Email enquiry'
AND (@customerID IS NULL OR cs.CustomerID = @customerID)
GROUP BY b.itemid)
SELECT a.Active,
a.ParentClass,
a.Classification,
a.Variant,
ISNULL(fv.num_full_Views, 0) AS "Full Views",
ISNULL(pv.num_print_views, 0) AS "Print Views",
ISNULL(ee.num_email_enquiries, 0) AS "Email Enquiries",
a.ItemRef,
a.SiteID
FROM items a
LEFT JOIN full_views fv ON fv.itemid = a.itemid
LEFT JOIN print_views pv ON pv.itemid = a.itemid
LEFT JOIN email_queries ee ON ee.itemid = a.itemid
为了获得更好的性能,我将其转换为动态SQL,以便删除这些参数检查:
AND (@siteID = -1 OR i.SiteID = @siteID)
...因为对sargability的负面影响。