2014-12-30 3 views
1

Вот теоретический сценарий,Динамические последовательности сервера Sql

Предположим, у меня есть таблица клиентов и таблица счетов. 1 клиент может иметь много счетов-фактур.

Теперь я хочу каждый счет, чтобы иметь номер счета, который является уникальным для данного клиента

т.е.

ClientId InvoiceNo 
1  IN0001 
2  IN0001 
2  IN0002 
2  IN0003 
3  IN0001 

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

Я читал на SEQENCE Sql Server 2012, который звучит великолепно , но проблема в том, что я по-прежнему нужна отдельная последовательность каждого клиента

т.е.

CREATE SEQUENCE InvoiceNum_Client1..... 
CREATE SEQUENCE InvoiceNum_Client2..... 
CREATE SEQUENCE InvoiceNum_Client3..... 

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

NEXT VALUE FOR InvoiceNum_Client + @ClientId 

и т.д.

Так что моя следующая мысль была иметь «последовательность» таблицы, т.е.

ClientID INSequenceNumber 
1   1 
2   3 
3   3 

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

Так что мои вопросы

  1. Есть ли большой недостаток в мой собственной прокатке метод последовательности?
  2. Есть ли еще одно решение, которое я, возможно, не замечаю?

Спасибо!

ответ

1

Есть ли конкретная причина требовать, чтобы номера счетов были уникальными только для каждого клиента? В большинстве систем ERP номера счетов, как правило, уникальны по всему миру, что значительно упрощает реализацию. Независимо от этого, у вас должна быть таблица счетов, содержащая первичный ключ (и вы не должны использовать составные первичные ключи - это просто плохое моделирование данных).

Это оставляет нам сценарий, в котором вам может вообще не понадобиться хранить «номер-клиент-счет-фактура» в базе данных. Предполагая, что у вас есть таблица под названием «Счета-фактуры», содержащий следующие данные:

Id | ClientId 
--------------- 
    1 |  1 
    2 |  1 
    3 |  2 
    4 |  1 
    5 |  3 
    6 |  2 

Здесь Id является первичный ключ таблицы Счета-фактуры, и ClientId является внешним ключом.Запрос, как это:

SELECT 
    ClientId, 
    'IN' + RIGHT('0000' + 
      CONVERT(VARCHAR, ROW_NUMBER() OVER (PARTITION BY ClientId 
               ORDER BY Id)) AS InvoiceNo, 
    Id 
FROM Invoices 
ORDER BY ClientId, InvoiceNo 

вернуться бы:

ClientId | InvoiceNo | Id 
--------------------------- 
     1 | IN0001 | 1 
     1 | IN0002 | 2 
     1 | IN0003 | 4 
     2 | IN0001 | 3 
     2 | IN0002 | 6 
     3 | IN0001 | 5 
+1

Очень хороший ответ спасибо. Я не понимал, что есть ключевые слова OVER/PARTITION BY. очень могущественный. Чтобы ответить на ваш 1-й вопрос, есть действительный прецедент для получения уникальных номеров счетов на каждого клиента. это общая система, используемая более чем одним клиентом, и каждый клиент полностью отделен друг от друга. Если я использую глобальную уникальную последовательность счетов, клиенты будут испытывать «дыры» в своих последовательностях счетов, и это заставит аудиторов задавать вопросы – Crudler

+1

. В этом случае вам обязательно нужно сохранить номера счетов-фактур в таблице. Но я боюсь, что оператор SEQUENCE не поможет вам в этом отношении. Вместо этого вы должны использовать подход таблицы, который вы предложили себе, или использовать MAX() вместе с механизмом блокировки для обеспечения того, чтобы дублированные номера счетов никогда не создавались. – Dan

+0

@ Dan. , , В SQL Server * никогда не используйте 'varchar' без длины. Вы никогда не знаете, будет ли достаточной длина по умолчанию в заданном контексте. Таким образом, вы должны иметь 'CONVERT (VARCHAR (255), ... (или любую вашу любимую длину). –

0

Почему клиенты должны иметь свои собственные последовательности? Имейте глобальный порядковый номер. Затем, если вы хотите, чтобы получить клиента последовательности в порядке, используйте row_number():

select i.*, row_number() over (partition by clientid order by invoiceno) as ClientInvoiceSequence 
from invoices; 

Примечание: может потребоваться, чтобы order by быть другим полем, такие как дата.

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

  • Что происходит, когда два счетов введены «в то же время»?
  • Что происходит, когда счет-фактура удаляется?
  • Что происходит, когда счет-фактура изменен таким образом, что он может изменить последовательность?

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

+0

Спасибо, тоже очень хороший ответ. Очень похоже на дан, но я дал ему очки, потому что он победил u до удара, хотя бы на несколько коротких секунд :) – Crudler

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