#sql #sql-server #tsql
#sql #sql-server #tsql
Вопрос:
У меня есть таблица со следующими столбцами: Имя автора, страна, статус.
Author_name country status
-------------------------------------------
1 Author - 1 Country - 1 name remove
2 Author - 2 Country - 2 name done
3 Author - 3 Country - 3 name done
4 Author - 4 Country - 4 name done
5 Author - 5 Country - 5 name done
6 Author - 6 Country - 6 name remove
7 Author - 7 Country - 7 name remove
8 Author - 8 Country - 8 name done
9 Author - 9 Country - 9 name remove
10 Author - 10 Country - 10 name done
Ожидаемая функциональность: при обнаружении «удалить» эта строка должна быть удалена, а строка над ней должна быть удалена.
Если «удалить» отображается последовательно, то необходимо удалить столько строк сверху. местоположение ‘remove’ и количество записей не являются постоянными.
После запуска SQL-скрипта вывод приведенной выше таблицы должен быть:
Author_name country status
-------------------------------------------
2 Author - 2 Country - 2 name done
3 Author - 3 Country - 3 name done
10 Author - 10 Country - 10 name done
Надеюсь, вы поняли логику.
Я также пробовал использовать лаг, курсор и некоторые другие. Теперь я пытаюсь использовать цикл while. Пожалуйста, помогите мне с этим. Вот мой последний код.
Моей базой данных является SQL Server, и в настоящее время я использую онлайн-компилятор:https://rextester.com/l/sql_server_online_compiler
CREATE Table tblAuthors
(
Author_name nvarchar(50),
country nvarchar(50),
prod varchar(50),
timestamp datetime
)
Declare @Id int
Set @Id = 1
While @Id <= 10
Begin
Insert Into tblAuthors values ('Author - ' CAST(@Id as nvarchar(10)),
'Country - ' CAST(@Id as nvarchar(10)) ' name', 'done', getdate())
Print @Id
Set @Id = @Id 1
End
update tblAuthors set prod = 'remove' where Author_name = 'Author - 1'
update tblAuthors set prod = 'remove' where Author_name = 'Author - 6'
update tblAuthors set prod = 'remove' where Author_name = 'Author - 7'
update tblAuthors set prod = 'remove' where Author_name = 'Author - 9'
SELECT * FROM tblAuthors
select IDENTITY(int, 1,1) as idnt,* into ##temp_tblAuthors from tblAuthors
select * from ##temp_tblAuthors
DECLARE @intFlag INT = 1
DECLARE @Flag INT = 0
DECLARE @Author_name nvarchar(50)
DECLARE @country nvarchar(50)
DECLARE @prod varchar(50)
DECLARE @idnt INT
select @Flag = count(*) from ##temp_tblAuthors
WHILE (@intFlag <=@Flag)
BEGIN
select
@idnt = idnt
,@Author_name = Author_name
,@country = country
,@prod = prod
from ##temp_tblAuthors where idnt = @intFlag
if @prod = 'remove'
BEGIN
SELECT @intFlag
select
@idnt = idnt
,@Author_name = Author_name
,@country = country
,@prod = prod
from ##temp_tblAuthors where idnt = @intFlag-1
DELETE tblAuthors WHERE
Author_name = @Author_name AND
country = @country AND
prod = @prod
select
@idnt = idnt
,@Author_name = Author_name
,@country = country
,@prod = prod
from ##temp_tblAuthors where idnt = @intFlag
DELETE tblAuthors WHERE
Author_name = @Author_name AND
country = @country AND
prod = @prod
END
SET @intFlag = @intFlag 1
END
GO
SELECT * FROM tblAuthors
Комментарии:
1. Наборы данных в SQL явно неупорядочены . Нет «строки выше». Вам нужен столбец (или колонок) , который вы можете использовать в
ORDER BY
для утверждения порядка. У вас есть такой столбец? (Например, временная метка, указывающая, когда была вставлена строка?)2. Привет @MatBailie да, есть столбец identity, надеюсь, мы сможем использовать то же самое.
3. Не гарантируется , что столбец идентификаторов находится в порядке, для строки возможно , что значение идентификатора ниже, чем у ранее существовавшей строки. (Рекомендуется никогда ничего не выводить из столбца identity и использовать его только как уникальный идентификатор) Есть ли у вас другие столбцы?
4. @MatBailie .. спасибо за ответ .. В настоящее время я разрабатываю базу данных, я могу добавить столбец временных меток. надеюсь, это решит проблему с порядком.
5. Добавлен столбец временной метки @MatBailie… Я все еще пытаюсь разобраться в процессе удаления.
Ответ №1:
Если вы работаете в обратном направлении, вы можете суммировать «оценку», где 'remove'
имеет -1
и 'done'
имеет 1
.
Author_name Country Status Score
------------------------------------------------------
1 Author - 1 Country - 1 name remove 2
2 Author - 2 Country - 2 name done 3
3 Author - 3 Country - 3 name done 2
4 Author - 4 Country - 4 name done 1
5 Author - 5 Country - 5 name done 0
6 Author - 6 Country - 6 name remove -1
7 Author - 7 Country - 7 name remove 0
8 Author - 8 Country - 8 name done 1
9 Author - 9 Country - 9 name remove 0
10 Author - 10 Country - 10 name done 1 <- Start from here
Пример SQL:
SELECT
*,
SUM(CASE WHEN status = 'remove' THEN -1 ELSE 1 END)
OVER (ORDER BY timestamp DESC, id DESC)
AS score
FROM
tblAuthors
Затем вы хотите сохранить только те строки, в которых (все еще работая в обратном направлении) оценка выше, чем когда-либо была до сих пор.
Author_name Country Status Score PreviousMax
--------------------------------------------------------------------
1 Author - 1 Country - 1 name remove 2 3
2 Author - 2 Country - 2 name done 3 2 <- KEEP
3 Author - 3 Country - 3 name done 2 1 <- KEEP
4 Author - 4 Country - 4 name done 1 1
5 Author - 5 Country - 5 name done 0 1
6 Author - 6 Country - 6 name remove -1 1
7 Author - 7 Country - 7 name remove 0 1
8 Author - 8 Country - 8 name done 1 1
9 Author - 9 Country - 9 name remove 0 1
10 Author - 10 Country - 10 name done 1 NULL <- KEEP
Вы можете сделать это с помощью…
WITH
scored_rows AS
(
SELECT
*,
SUM(CASE WHEN status = 'remove' THEN -1 ELSE 1 END)
OVER (ORDER BY timestamp DESC, id DESC)
AS score
FROM
tblAuthors
),
checked_scored_rows AS
(
SELECT
*,
MAX(score)
OVER (ORDER BY timestamp DESC, id DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
)
AS previous_max_score
FROM
scored_rows
)
SELECT
*
FROM
checked_scored_rows
WHERE
score > COALESCE(previous_max_score, 0)
;
Это тоже приводит вас…
WITH
scored_rows AS
(
SELECT
*,
SUM(CASE WHEN status = 'remove' THEN -1 ELSE 1 END)
OVER (ORDER BY timestamp DESC, id DESC)
AS score
FROM
tblAuthors
),
checked_scored_rows AS
(
SELECT
*,
MAX(score)
OVER (ORDER BY timestamp DESC, id DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING
)
AS previous_max_score
FROM
scored_rows
)
DELETE
tblAuthors
FROM
checked_scored_rows
WHERE
checked_scored_rows.id = tblAuthors.id
AND checked_scored_rows.score <= COALESCE(checked_scored_rows.previous_max_score, 0)
Я считаю, что это демонстрирует то, что вы хотите: https://rextester.com/ZNNB32798