我有一个SQL Server数据库。我需要在表格中循环以获取列中的每个值的计数' RevID'。每个值应仅在表中显示一定次数 - 例如125次。如果值的计数大于125或小于125,我需要更新列以确保RevID中的所有值(超过25个不同的值)都在125的相同范围内(可以关闭几个数字) )
例如,RevID的计数=" A2"是= 45并且RevID =' B2'是= 165然后我需要更新RevID,因此45计数增加,165减少,直到它们在125范围内。
这是我到目前为止所做的:
Test: ascii7
Pass
Test: Latin-1
Pass
Test: UTF-8
Pass
我也玩过光标而不是触发器。有关如何实现这一点的任何想法?感谢您的任何意见。
答案 0 :(得分:0)
好的,我回想一下,因为我发现它很有趣,尽管很明显你和我以及其他人都没有看到一些商业规则/讨论。无论如何,如果你想要均匀地和随意分配,你可以通过构建递归公用表表达式[CTE]或通过构建临时表等来实现它。无论如何这里是一种我决定试一试的方法,我确实利用了1个临时表,因为sql与主逻辑表有点不一致作为cte大约每10次但是临时表似乎已经清除了。无论如何,这将任意地均匀地传播RevId并随机地将任何余数(记录数/ RevIds数)分配给其中一个RevId。这个脚本也不依赖于具有UniqueID或它在它创建的行号上动态工作的任何东西......在这里你只需减去测试数据等,你就拥有了你可能想要的东西。虽然重建表/值可能会更容易。
--Build Some Test Data
DECLARE @Table AS TABLE (RevId VARCHAR(10))
DECLARE @C AS INT = 1
WHILE @C <= 400
BEGIN
IF @C <= 200
BEGIN
INSERT INTO @Table (RevId) VALUES ('A1')
END
IF @c <= 170
BEGIN
INSERT INTO @Table (RevId) VALUES ('B2')
END
IF @c <= 100
BEGIN
INSERT INTO @Table (RevId) VALUES ('C3')
END
IF @c <= 400
BEGIN
INSERT INTO @Table (RevId) VALUES ('D4')
END
IF @c <= 1
BEGIN
INSERT INTO @Table (RevId) VALUES ('E5')
END
SET @C = @C+ 1
END
--save starting counts of test data to temp table to compare with later
IF OBJECT_ID('tempdb..#StartingCounts') IS NOT NULL
BEGIN
DROP TABLE #StartingCounts
END
SELECT
RevId
,COUNT(*) as Occurences
INTO #StartingCounts
FROM
@Table
GROUP BY
RevId
ORDER BY
RevId
/************************ This is the main method **********************************/
--clear temp table that is the main processing logic
IF OBJECT_ID('tempdb..#RowNumsToChange') IS NOT NULL
BEGIN
DROP TABLE #RowNumsToChange
END
--figure out how many records there are and how many there should be for each RevId
;WITH cteTargetNumbers AS (
SELECT
RevId
--,COUNT(*) as RevIdCount
--,SUM(COUNT(*)) OVER (PARTITION BY 1) / COUNT(*) OVER (PARTITION BY 1) +
--CASE
--WHEN ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY NEWID()) <=
--SUM(COUNT(*)) OVER (PARTITION BY 1) % COUNT(*) OVER (PARTITION BY 1)
--THEN 1
--ELSE 0
--END as TargetNumOfRecords
,SUM(COUNT(*)) OVER (PARTITION BY 1) / COUNT(*) OVER (PARTITION BY 1) +
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY NEWID()) <=
SUM(COUNT(*)) OVER (PARTITION BY 1) % COUNT(*) OVER (PARTITION BY 1)
THEN 1
ELSE 0
END - COUNT(*) AS NumRecordsToUpdate
FROM
@Table
GROUP BY
RevId
)
, cteEndRowNumsToChange AS (
SELECT *
,SUM(CASE WHEN NumRecordsToUpdate > 1 THEN NumRecordsToUpdate ELSE 0 END)
OVER (PARTITION BY 1 ORDER BY RevId) AS ChangeEndRowNum
FROM
cteTargetNumbers
)
SELECT
*
,LAG(ChangeEndRowNum,1,0) OVER (PARTITION BY 1 ORDER BY RevId) as ChangeStartRowNum
INTO #RowNumsToChange
FROM
cteEndRowNumsToChange
;WITH cteOriginalTableRowNum AS (
SELECT
RevId
,ROW_NUMBER() OVER (PARTITION BY RevId ORDER BY (SELECT 0)) as RowNumByRevId
FROM
@Table t
)
, cteRecordsAllowedToChange AS (
SELECT
o.RevId
,o.RowNumByRevId
,ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY (SELECT 0)) as ChangeRowNum
FROM
cteOriginalTableRowNum o
INNER JOIN #RowNumsToChange t
ON o.RevId = t.RevId
AND t.NumRecordsToUpdate < 0
AND o.RowNumByRevId <= ABS(t.NumRecordsToUpdate)
)
UPDATE o
SET RevId = u.RevId
FROM
cteOriginalTableRowNum o
INNER JOIN cteRecordsAllowedToChange c
ON o.RevId = c.RevId
AND o.RowNumByRevId = c.RowNumByRevId
INNER JOIN #RowNumsToChange u
ON c.ChangeRowNum > u.ChangeStartRowNum
AND c.ChangeRowNum <= u.ChangeEndRowNum
AND u.NumRecordsToUpdate > 0
IF OBJECT_ID('tempdb..#RowNumsToChange') IS NOT NULL
BEGIN
DROP TABLE #RowNumsToChange
END
/***************************** End of Main Method *******************************/
-- Compare the results and clean up
;WITH ctePostUpdateResults AS (
SELECT
RevId
,COUNT(*) as AfterChangeOccurences
FROM
@Table
GROUP BY
RevId
)
SELECT *
FROM
#StartingCounts s
INNER JOIN ctePostUpdateResults r
ON s.RevId = r.RevId
ORDER BY
s.RevId
IF OBJECT_ID('tempdb..#StartingCounts') IS NOT NULL
BEGIN
DROP TABLE #StartingCounts
END
答案 1 :(得分:0)
由于您没有给出如何操作余额的规则,我们只能进行推测。这是一种方法,可以找到代表性最高的价值,然后找到一个可以承担整个超额的代表性不足的价值。
我不知道这是多么优化,它可能会在没有更多逻辑的无限循环中运行。
declare @balance int = 125;
declare @cnt_over int;
declare @cnt_under int;
declare @revID_overrepresented varchar(32);
declare @revID_underrepresented varchar(32);
declare @rowcount int = 1;
while @rowcount > 0
begin
select top 1 @revID_overrepresented = RevID, @cnt_over = count(*)
from T
group by RevID
having count(*) > @balance
order by count(*) desc
select top 1 @revID_underrepresented = RevID, @cnt_under = count(*)
from T
group by RevID
having count(*) < @balance - @cnt_over
order by count(*) desc
update top @cnt_over - @balance T
set RevId = @revID_underrepresented
where RevId = @revID_overrepresented;
set @rowcount = @@rowcount;
end
答案 2 :(得分:-1)
问题是我甚至不知道你的意思是什么...你说它需要均匀表示但似乎你想要它是125. 125不是“偶数”,它只是125
我不知道你要做什么,但我猜这不是一个真正的SQL问题。但您可以使用SQL来提供帮助。这是一些有用的SQL。您可以使用您选择的语言来解决问题。
查找转速值及其计数:
SELECT RevID, COUNT(*)
FROM MyTable
GROUP BY MyTable
将@X行(RevID值为@RevID)更新为新值@NewValue
UPDATE TOP @X FROM MyTable
SET RevID = @NewValue
WHERE RevID = @RevID
使用这两个查询,您应该能够在循环中应用业务规则(您从未指定过)或更改数据。