2016-08-17 2 views
2

Код ниже SQL Server успешно вычисляет и вставляет ежемесячную оплату для всех сотрудников вместе с их номером staffID и вставляет его в Tablepayroll.SQL Server: автоматически добавляет уникальный идентификатор ко всем вставленным за один раз столбцам

INSERT INTO Tablepayroll (StaffID,Totalpaid) 
(SELECT Tabletimelog.StaffID , Tabletimelog.hoursworked * Tablestaff.hourlypay 
FROM Tabletimelog 
JOIN Tablestaff ON 
Tabletimelog.StaffID = Tablestaff.StaffID) 

Однако, я хочу, чтобы иметь возможность также вставить batchID, так что вы можете идентифицировать каждый раз выше вставка была запущена и записи, вставленные им в то время. Это означает, что все зарплаты сотрудников, рассчитанные в одно и то же время, будут иметь тот же номер batchID. Каждый последующий batchID должен просто увеличиваться на 1.

Для получения пояснения обратитесь к изображению ниже.

enter image description here

Я думаю, что Select MAX(batch_id) + 1 будет работать, но я не знаю, как включить его в операторе вставки.

+0

Случайная мысль: создайте триггер, который вставляет одну запись во вторую таблицу с столбцом автоматического увеличения. Используйте это, чтобы отслеживать каждую партию. –

+3

Я бы не использовал MAX (BatchID) + 1 или идею вставки записи в фиктивную таблицу. Вы должны смотреть в последовательности. https://msdn.microsoft.com/en-us/library/ff878091.aspx То, что вы описали, в точности соответствует тем, для каких последовательностей предназначены. –

+3

Не будет ли хранить дату вставки намного более значимой, чем последовательность? Если вам нужно сгенерировать целое число из этого, вы можете использовать - 'Batch_id = DENSE_RANK() OVER (ORDER BY CreatedDate DESC)' – GarethD

ответ

2

Вы можете использовать подзапрос, чтобы найти последние batch_id из текущей таблицы, используя этот запрос:

INSERT INTO TablePayroll (StaffID, TotalPaid, batch_id) 
SELECT T1.StaffID 
    , T1.HoursWorked * T2.HourlyPay 
    , ISNULL((SELECT MAX(batch_id) FROM TablePayRoll), 0) + 1 AS batch_id 
FROM TableTimeLog AS T1 
INNER JOIN TableStaff AS T2 
    ON T1.StaffID = T2.StaffID; 

Как вы можете видеть, я просто добавить 1 к текущему MAX(batch_id) и это все.
Кстати, научитесь использовать псевдонимы. Это сделает вашу жизнь проще

Еще одно решение будет иметь ваш batch_id как GUID, поэтому вам не нужно создавать последовательности или получать MAX(batch_id) из текущей таблицы.

DECLARE @batch_id UNIQUEIDENTIFIER = NEWID(); 

INSERT INTO TablePayroll (StaffID, TotalPaid, batch_id) 
SELECT T1.StaffID, T1.HoursWorked * T2.HourlyPay, @batch_id 
FROM TableTimeLog AS T1 
INNER JOIN TableStaff AS T2 
    ON T1.StaffID = T2.StaffID; 
+2

Для первого вхождения/партии необходимо проверить значение null и сделать это 0, иначе все будет NULL. но кроме этого хорошо выглядит – Matt

+0

@Matt Это правда. Я сделаю изменения в запросе :) 'COALESCE' должен делать все отлично. –

+1

Несмотря на то, что он не является стандартом ANSI, я мог бы использовать 'ISNULL' вместо' COALESCE' здесь, 'COALESCE' приведет к тому, что подзапрос будет выполняться дважды из-за того, как он распространяется на выражение case -' CASE WHEN (SELECT ...) NULL THEN 0 ELSE (SELECT ...) END'. Дополнительные различия см. В разделе [Определение между COALESCE и ISNULL в SQL Server] (https://www.mssqltips.com/sqlservertip/2689/deciding-between-coalesce-and-isnull-in-sql-server/) – GarethD

0

Обновлено

Прежде всего получить максимальное значение в большой таблице (на основе имени таблицы должно быть большим) может быть очень дорогим. Особенно, если на колонке нет индекса batch_id

Во-вторых, обратите внимание на ваше решение. SELECT MAX(batch_id) + 1 может вести себя некорректно, если у вас будут конкурентоспособные вставки. Решение от @EvaldasBuinauskas без открытия транзакции и правового уровня изоляции также может привести к тому же batch_id, если вы одновременно запускаете две вставки одновременно.

Если ваш SQL Server версии 2012 или более высокий вы можете попробовать SEQUENCE. Это, по крайней мере, гарантирует, что дубликаты batch_id

не Создание SEQUENCE:

CREATE SEQUENCE dbo.BatchID 
    START WITH 1 
    INCREMENT BY 1 ; 
-- DROP SEQUENCE dbo.BatchID 
GO 

И использовать его:

DECLARE @BatchID INT 
SET @BatchID = NEXT VALUE FOR dbo.BatchID; 

INSERT INTO Tablepayroll (StaffID,Totalpaid, batch_id) 
(SELECT Tabletimelog.StaffID , Tabletimelog.hoursworked * Tablestaff.hourlypay, @BatchID 
    FROM Tabletimelog 
     JOIN Tablestaff ON Tabletimelog.StaffID = Tablestaff.StaffID) 

Альтернативой SEQUENCE может быть дополнительная таблица:

CREATE TABLE dbo.Batch (
    ID INT NOT NULL IDENTITY 
     CONSTRAINT PK_Batch PRIMARY KEY CLUSTERED 
    ,DT DATETIME 
     CONSTRAINT DF_Batch_DT DEFAULT GETDATE() 
); 

Это решение работает даже в старой версии ser веры.

DECLARE @BatchID INT 

INSERT INTO dbo.Batch (DT) 
    VALUES (GETDATE()); 

SET @BatchID = SCOPE_IDENTITY(); 

INSERT INTO Tablepayroll (StaffID,Totalpaid, batch_id) 
(SELECT Tabletimelog.StaffID , Tabletimelog.hoursworked * Tablestaff.hourlypay, @BatchID 
    FROM Tabletimelog ... 

И да, все эти решения не гарантируют отсутствие отверстий в нумерации. Это может произойти во время откат транзакции (тупик для ex.)

+0

Thankyou Alex, я постараюсь понять последующие последовательности. – Jacksql

Смежные вопросы