2013-07-27 3 views
2

Я хочу сгенерировать значения первичного ключа с расширением первичного ключа varchar (порядок id) для каждого отдельного заказа, помещенного как показано ниже.Сгенерировать автоинкрементный первичный ключ varchar в sql-сервере

'O201307270001'

'O' для заказа, '20130727' на дату (27-июль-2013), '0001' для автоматического увеличивающегося значения

я хочу перезапустить автоматически увеличивающиеся цифры (последние 4 номера в указанном выше id) начинаются с '1', когда начинается новый день.

Ниже приведены примеры, как я хочу идентификаторы порядка, которые будут созданы для того, помещают в разное время и день:

O201307270001 when date is like '2013-07-27 01:23:45.235' 
O201307270002 when date is like '2013-07-27 03:12:22.212' 
. 
. 
. 
O201307270040 when date is like '2013-07-27 11:34:56.189' 
. 
. 
//Now when new day starts: 
O201307280001 when date is like '2013-07-28 00:00:00.000' 
O201307280002 when date is like '2013-07-28 00:13:05.000' 

пожалуйста, помогите мне, как я могу это сделать

+0

Посмотрите на это [ответ] (http://stackoverflow.com/questions/17745713/sql-statement-to-retrieve-the-last -Посещение значение, из-баз данных/17746628 # 17746628). –

+0

Помог ли вам любой из ответов? – jpw

ответ

2

Вот что я предлагаю, у которого есть (довольно большое :)) преимущество в том, что вы не читаете целевой стол и не получите лучшую производительность по мере роста вашей таблицы.

Вам нужно будет создать короткую хранимую процедуру и таблицу параметров.

Просто вызвать хранимую процедуру и возвращает правильный Id:

DECLARE @NewOrderId AS CHAR(13) 

EXEC usp_NewOrderId @NewOrderId OUTPUT 

SELECT @NewOrderId 

Это то, что вам нужно создать:

CREATE TABLE OrderNumberGenerator (
    Id INTEGER IDENTITY(1,1), 
    CreatedDate DATE DEFAULT(GETDATE()) 
) 
GO 

CREATE PROCEDURE usp_NewOrderId 
(@NewOrderIdOut char(13) OUTPUT) 
AS 
BEGIN 

    IF EXISTS (SELECT 1 FROM OrderNumberGenerator WHERE CreatedDate <> CAST(GETDATE() AS DATE)) 
    TRUNCATE TABLE OrderNumberGenerator --restart the counter everyday :) 

    INSERT INTO OrderNumberGenerator DEFAULT VALUES 

    SELECT @NewOrderIdOut = 
    'O' + 
    CONVERT(CHAR(8), GETDATE(), 112) + 
    RIGHT('000' + CAST(SCOPE_IDENTITY() AS VARCHAR(4)) , 4) 

END 

Проверьте это здесь http://sqlfiddle.com/#!3/fdb91/4

+0

Большое спасибо! Просто работал точно. :) –

0

Я настоятельно рекомендую вы не должны использовать этот код, сгенерированный varchar, в качестве первичного ключа вашей таблицы, вместо этого используйте численное значение и сохраните эту сгенерированную строку в виде кода заказа в отдельном столбце (он будет держать вас подальше от кошмаров с будущими запросами). Вы можете пометить этот столбец кода как «уникальный» и получить тот же результат.

О том, как сгенерировать код заказа, если логика позади не такая простая, как автоинкремент, или что-то в этом роде, было бы лучше иметь эту донду на верхнем уровне вашей системы (если она есть).

+0

Varchar может использоваться в качестве первичных ключей, этот номер заказа не будет плохим выбором для ПК. Ключи связаны с бизнесом, когда дело доходит до индексов и проблем с производительностью, это не проблема. Даже если я считаю, что этот столбец можно использовать как кластеризованный индекс, так как он последовательно генерируется – jazzytomato

+0

«Varchar может использоваться как первичный ключ», конечно, я не говорю, что они не могут. «Ключи связаны с бизнесом», ну, я должен не соглашаться здесь, я думаю, что в большинстве случаев мы используем ключи как идентификаторы наших бизнес-объектов, но они не совпадают, как в этой таблице пользователей: UserId - - Ключ, связанный или не связанный с бизнес-логикой Email - Идентификатор, связанный с BL FirstName –

+0

Просто говорите, что ключи являются логическими отношениями, тогда как индексы относятся к хранению и производительности. Вы смешиваете эти две концепции в своем ответе. – jazzytomato

0

Вы можете сделать это с помощью триггера INSTEAD OF INSERT или, как я бы рекомендовал, хранимую процедуру CreateOrder.

Вот шаги, которые вы должны следовать:

  1. Compute текущий префикс даты. 'O' + CONVERT(char(8), GETDATE(), 112)
  2. Выберите последний номер заказа из таблицы. SELECT MAX(OrderNum) FROM Order
  3. Если последний номер заказа имеет префикс текущей даты, извлеките числовой суффикс, увеличьте его и добавьте в префикс даты. WHEN @CurrentPrefix = LEFT(@LastOrder, 9) THEN @CurrentPrefix + RIGHT('000' + (CONVERT(int, RIGHT(@LastOrder, 4)) + 1))
  4. В противном случае просто используйте 0001 в качестве суффикса. ELSE @CurrentPrefix + '0001'
  5. Используйте сгенерированный ключ для выполнения вставки.
0

Попробуйте

DECLARE @autoInc VARCHAR(25) 
SET @autoInc='O'+(SELECT convert(varchar, getdate(), 112))+ 
       CAST(((SELECT COUNT(*) 
        FROM table 
       WHERE autoColumn like 'O'+(SELECT convert(varchar, getdate(),112))+'%') 
         +1) AS VARCHAR(5)) 
+1

'SELECT COUNT (*)' не работает, если заказ удаляется из предыдущего дня. – Gabe

+0

ya. такая проблема есть. спасибо, Гейб. я не заметил, что – Nithesh

0

Как и другие ответы уже отметил, делая это может быть плохой идеей, но если вы хотите, чтобы в любом случае этот код должен выполнить то, что вы хотите, я считаю. Я не пробовал все угловые случаи, но для небольших тестовых данных при условии, что он работает.

Некоторые тестовые данные, которые я пробовал:

declare @tab table (pk char(13)) 
insert @tab values ('O201307270001') 
insert @tab values ('O201307270002') 
insert @tab values ('O201307270003') 
insert @tab values ('O201307278999') 
insert @tab values ('O201307280001') 
insert @tab values ('O201307280002') 
insert @tab values ('O201307290001') 

А потом фактический код:

SELECT 
    CASE ISNULL(MAX(RIGHT(pk,4)),0) 
    WHEN 0 THEN 'O' + CONVERT(CHAR(8),GETDATE(),112) + '0001' 
    ELSE 'O' + CONVERT(CHAR(8),GETDATE(),112) + RIGHT(CAST(MAX(RIGHT(pk,4)) + 10001 AS CHAR(5)),4) END 
FROM @tab 
WHERE SUBSTRING(pk,2,8) = CONVERT(CHAR(8),GETDATE(),112) 

В идеале она должна быть завернута в функции, и, возможно, использовать блокировку слишком, чтобы избежать такой же ключ выдается дважды.

0

CREATE TABLE OrderNumberGenerator ( [ID] INTEGER IDENTITY (1,1), [new_id] AS 'O' + CONVERT (VARCHAR) ) GO

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