尝试查看索引在SQL中的工作方式。这不是一张桌子,而是更多的清单?在C#或其他语言中,我们使用array[i]
作为获取特定项的语法的数组。我如何获取5号ID?这是基本代码,我打算将其放入更大的代码中,例如递增for
循环以递增每个ID。目的:从记录历史记录表中删除需要太长时间并影响生产。希望将其批量处理为较小的事务以删除过时的记录。
DECLARE @Cust_NoHolds TABLE(IDs VARCHAR(100))
INSERT INTO @Cust_NoHolds SELECT '0'
INSERT INTO @Cust_NoHolds SELECT '1'
INSERT INTO @Cust_NoHolds SELECT '2'
INSERT INTO @Cust_NoHolds SELECT '3'
INSERT INTO @Cust_NoHolds SELECT '4'
INSERT INTO @Cust_NoHolds SELECT '5'
INSERT INTO @Cust_NoHolds SELECT '6'
INSERT INTO @Cust_NoHolds SELECT '7'
INSERT INTO @Cust_NoHolds SELECT '8'
INSERT INTO @Cust_NoHolds SELECT '9'
SELECT IDs FROM @Cust_NoHolds WITH (INDEX(1)) --this is obviously wrong
答案 0 :(得分:3)
关系数据库表没有自然顺序 - 与一个逻辑上有一个项目的数组不同,数据库行与另一行没有关系。它看起来就像选择数据时那样,因为它以某种方式存储和检索,但这是数据库实现的结果。
因此,在数据库术语中,删除第5行并不是很有意义,但是删除按行XXX排序数据时出现的第5行是有意义的。虽然在实践中您倾向于删除列XXX具有值YYY的行(或行集)。
您可以将某个索引视为在某个表格上强加某种顺序(但这并不是它们的主要目的)。
答案 1 :(得分:3)
如果您想跟踪表格上的广告订单顺序,请使用identity
列:
DECLARE @Cust_NoHolds TABLE(
id int identity,
IDs VARCHAR(100)
);
然后对于插入,使用显式列列表:
INSERT INTO @Cust_NoHolds(ids) SELECT '0' --crude, but basic. forgive me.
现在,您有一个具有插入顺序的单调递增数字。因此,获得第五条记录的一种方法是:
select *
from @Cust_NoHolds
order by id
offset 4
fetch first 1 row only;
对于offset
,0是第一行,所以4是第五行。 SQL Server 2012+中提供了此语法;在早期版本中,您需要使用子查询两次TOP
。此外,order by
很重要,因为除非order by
子句指定了排序,否则结果集(如表)是无序的。
请注意,标识列保证会增加,但它们可能会有间隙。
答案 2 :(得分:1)
我将把这些烂摊子放在这里,以提供一个例子(并提醒自己),无论我们编写多长时间,总会有经验教训。我要非常感谢Conrad Frix,Pieter Geerkens,Gordon Linoff和目的地数据让我从另一个角度来看待这个问题。我的目标是将这个大型任务批量化为较小的任务,我可以在单独的单个查询中进行管理。以下是我的想法,它非常适合我想要完成的任务。再次感谢前面提到的这个主题的贡献者,以及其他每个人都在尝试。下面使用SQL体系结构优于数组,并且看起来比我的“数组模拟”原型更有效。
DECLARE @Cust_NoHolds TABLE(IDs VARCHAR(100))
INSERT INTO @Cust_NoHolds
SELECT DISTINCT CI.Custodian_Id
FROM custodian_info CI
--WHERE "stuff" (it's a massive union of two massive join statements)
DECLARE @historyIDs TABLE(histIDs VARCHAR(100)) --New values with each batch run!
INSERT INTO @historyIDs
SELECT Custodian_History_Id
FROM custodian_history CH
WHERE CH.Custodian_Id IN (Select IDs FROM @Cust_NoHolds)
--SELECT * FROM @historyIDs ORDER BY histIDs --takes 29 seconds to get to this point
DELETE custodian_history
FROM custodian_history CH
WHERE CH.Custodian_History_Id IN (Select TOP 100 histIDs FROM @historyIDs) --TOP X represents my batch
--Re-running this full sql file will take on the next X IDs in sequence, effectively making a functional batch.
答案 3 :(得分:0)
一种方法是使用TOP限制已删除记录的数量。
示例数据
/* Table variables making sharing sample data easy.
*/
DECLARE @Sample TABLE
(
Id INT
)
;
INSERT INTO @Sample
(
Id
)
VALUES
(1),
(2),
(3)
;
此查询是在SQL Server 2008 R2中构建和测试的。如果它不起作用,请在问题中添加正确的产品标签。
/* You can limit the number of records that are deleted.
*/
DELETE TOP (1)
FROM
@Sample
;
/* Two of the original three records will remain.
* There is no guarantee which these will be.
*/
SELECT
*
FROM
@Sample
;
此查询删除三个示例记录中的一个并返回另外两个。您可以与WHILE结合使用,直到删除了所有必需的记录。
编辑:您可能会发现更好的方法是确定原始查询效果不佳的原因。 Stack DBA可以提供帮助,如果您可以提供查询计划和某些背景信息。
答案 4 :(得分:0)
如果您可以从另一个表或表中识别要删除的记录,则可以将此逻辑移到delete语句中。这种方法避免了循环,这对SQL的优势没有影响。
示例使用两个表。 @Target是我们要删除的表。 @ToDelete包含@Target中不再需要的行。
示例数据
/* Table variables making sharing sample data easy.
*/
DECLARE @Target TABLE
(
Id INT
)
;
DECLARE @ToDelete TABLE
(
Id INT
)
;
INSERT INTO @Target
(
Id
)
VALUES
(1),
(2),
(3)
;
INSERT INTO @ToDelete
(
Id
)
VALUES
(1),
(2)
;
在示例中,我已过滤@ToDelete以限制已删除的记录。
示例强>
/* You can use the WHERE clause to filter the
* records you are going to delete.
*/
DELETE
FROM
@Target
FROM
@Target AS t
INNER JOIN @ToDelete AS td ON td.Id = t.Id
WHERE
td.Id = 2
;
/* Id 2 has been removed.
* It appeared in both tables and the WHERE clause of the DELETE statement.
*/
SELECT
*
FROM
@Target
;
答案 5 :(得分:-1)
尽管有关如何在SQL中使用数组的争论,但在这里,孩子们......在SQL中是一个“数组”。 SQL Server 2008
+-------+-----------+-----------+-----------+
| own | success | fail | pending |
+-------+-----------+-----------+-----------+
| BN | 3 | 0 | 0 |
| BB | 2 | 1 | 0 |
| BD | 1 | 1 | 1 |
| BC | 0 | 0 | 1 |