CJM*_*CJM 5 t-sql sql-server optimization
我正在努力将来自第三方系统的一些数据集成到我的一个应用程序(传统的基于ASP Classic的Web应用程序/ SQL 2000)中 - 当涉及到他们的方法和数据结构时,他们做出了一些糟糕的决定(恕我直言)虽然也许我们可能在某个时候有机会重构......但在那之前,我必须与我面前的事情一起工作.
主表保存检查数据,其中一个字段用于记录是否观察到某些特征.这些特性存储在一个名为的表中Categories,但不幸的是,主检查表(Test)通过将相关的CategoryIDs 连接到一个字段(SelectedCategories)来链接到类别.因此,例如,如果观察到特征01和02,则SelectedCategories该行的列Test将具有值"01C02C".
修剪DDL:
CREATE TABLE [dbo].[Test](
[ItemID] [varchar](255) NOT NULL,
[Result] [varchar](255) NULL,
[Comments] [varchar](255) NULL,
[ResultReason] [varchar](255) NULL,
[ImageLocation] [varchar](255) NULL,
[TestDateTime] [smalldatetime] NOT NULL,
[SelectedCategories] [varchar](255) NULL)
Run Code Online (Sandbox Code Playgroud)
问题是,鉴于这种情况,我如何才能最好地从Test观察到的特征细分中提取数据?
我想要的客户端上的输出是一个包含以下列的表:Test.PK,Test.Field2 ... Test.Fieldn,Categories.ID1,Categories.ID2,Categories.IDn
这可能不够清楚 - 第一个字段将是通常的嫌疑人Test,然后是每个类别的刻度线或交叉(或其他视觉指示符)Categories.
显然,如果这可以在一个查询中实现,那么在效率和性能方面就更好了.但是,我不确定如何实现这一目标 - 你将如何Categories通过该表加入SelectedCategories?
我显然可以简单地报告该SelectedCategories值并让应用程序解析该值.这可能是硬编码的,或者更有可能我们会重新查询CategoriesTest中的每一行 - 尽管这会产生性能影响.TBH,在这种情况下表现可能不是问题,但仅仅因为你可以逃避某些事情,并不意味着你应该养成它的习惯.
同样,如果我有机会重构第三方应用程序,我会删除SelectedCategories列并添加到TestCategories表中吗?或者我会将每个类别硬编码为一系列Bit列.很可能,在Categories系统的整个生命周期中都不会改变,但是如果它们这样做,则意味着DB和应用程序都会发生变化(尽管很小).
我希望我已经足够清楚地解释了它.从本质上讲,我说如果我坚持使用当前的系统,最好的方法是什么?如果我要重构,我可以采取什么不同的方法?
进度更新:
非常感谢列文,我到目前为止:
DML:
SELECT c.ID, c.Category, t.FilterID, t.OperatorResult, t.SelectedCategories
FROM dbo.Categories c
inner JOIN dbo.Test t ON CHARINDEX(Cast(c.ID as varchar), t.SelectedCategories, 1) <> 0
order by FilterID, ID
Run Code Online (Sandbox Code Playgroud)
输出:
ID Category FilterID OperatorResult SelectedCategories
4 Cracked Ceramic 137667 FAILED 04C
4 Cracked Ceramic 284821 FAILED 04C
4 Cracked Ceramic 287617 FAILED 04C05C
5 Damaged Case 287617 FAILED 04C05C
4 Cracked Ceramic 310112 FAILED 04C05C
5 Damaged Case 310112 FAILED 04C05C
Run Code Online (Sandbox Code Playgroud)
这就足够了,只是为了达到我想要的屏幕输出......
Filter ID Operator Result Cat Matl Crack Damage High Soot
137667 FAILED X X
178643 FAILED
284821 FAILED X
287617 FAILED X X
310112 FAILED X X
Run Code Online (Sandbox Code Playgroud)
...我要么需要进一步研究SQL(这样我只需要在一个查询中实现所需的输出),或者我需要在应用程序本身做一些额外的工作.
结论:
如果我们看看Lieven的最新示例(下面),我们可以看到问题可以在TSQL中解决,但类别是硬编码的.
替代方案是坚持原始数据并使IIS/ASP做更多工作.它会使源代码复杂化,但如果添加或删除类别,将消除更新TSQL的潜在开销.我当然可以忍受更新TSQL的这种非常偶然的需求,但我正在考虑类别表将定期主动更改的不同问题.
Categories通过以下方式加入表SelectedCategories可以这样工作
一些需要考虑的事情
让我们知道它是否对您有用。
BEGIN TRAN
CREATE TABLE [dbo].[Categories](
[CategorieID] INTEGER NOT NULL)
CREATE TABLE [dbo].[Test](
[ItemID] [varchar](255) NOT NULL,
[Result] [varchar](255) NULL,
[Comments] [varchar](255) NULL,
[ResultReason] [varchar](255) NULL,
[ImageLocation] [varchar](255) NULL,
[TestDateTime] [smalldatetime] NOT NULL,
[SelectedCategories] [varchar](255) NULL)
INSERT INTO dbo.Categories VALUES (4)
INSERT INTO dbo.Categories VALUES (5)
INSERT INTO dbo.Test VALUES (137667, 'FAILED', NULL, 'Cracked Ceramic', NULL, GetDate(), '04C')
INSERT INTO dbo.Test VALUES (284821, 'FAILED', NULL, 'Cracked Ceramic', NULL, GetDate(), '04C')
INSERT INTO dbo.Test VALUES (287617, 'FAILED', NULL, 'Cracked Ceramic', NULL, GetDate(), '04C05C')
INSERT INTO dbo.Test VALUES (287617, 'FAILED', NULL, 'Damaged Case' , NULL, GetDate(), '04C05C')
INSERT INTO dbo.Test VALUES (310112, 'FAILED', NULL, 'Cracked Ceramic', NULL, GetDate(), '04C05C')
INSERT INTO dbo.Test VALUES (310112, 'FAILED', NULL, 'Damaged Case' , NULL, GetDate(), '04C05C')
SELECT [Filter ID] = t.ItemID
, [Operator Result] = t.Result
, [Reason] = t.ResultReason
INTO #Output
FROM dbo.Categories c
LEFT OUTER JOIN dbo.Test t ON
/* Search for "C<{00}CategorieID>C" */
CHARINDEX('C' -- Prefix CategorieID & SelectedCategories with 'C'
+ REPLICATE('0', 2 - LEN(CAST(CategorieID AS VARCHAR))) -- Left Pad CategorieID with '0'
+ CAST(CategorieID AS VARCHAR) -- Add CategorieID itself
+ 'C' -- Suffix search string with 'C'.
, 'C' + t.SelectedCategories -- Prefix CategorieID & SelectedCategories with 'C'
, 1) <> 0
SELECT [Filter ID]
, [Operator Result]
, [Cat Matl] = CASE WHEN [Cat Matl] = 1 THEN 'X' ELSE '' END
, [Crack] = CASE WHEN [Crack] = 1 THEN 'X' ELSE '' END
, [Damage] = CASE WHEN [Damage] = 1 THEN 'X' ELSE '' END
, [High Soot] = CASE WHEN [High Soot] = 1 THEN 'X' ELSE '' END
FROM (
SELECT [Filter ID]
, [Operator Result]
, [Cat Matl] = MAX(CASE WHEN Reason = 'Cat Matl' THEN 1 ELSE 0 END)
, [Crack] = MAX(CASE WHEN Reason = 'Cracked Ceramic' THEN 1 ELSE 0 END)
, [Damage] = MAX(CASE WHEN Reason = 'Damaged Case' THEN 1 ELSE 0 END)
, [High Soot] = MAX(CASE WHEN Reason = 'High Soot' THEN 1 ELSE 0 END)
FROM #Output
GROUP BY [Filter ID]
, [Operator Result]
) o
DROP TABLE #Output
ROLLBACK TRAN
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
130 次 |
| 最近记录: |