這個答案集中在如何從公司前綴的新產品分配UPC代碼時,在有「缺口」序列或您正在重複使用來自不活動產品的UPC代碼(不推薦)。
UPC代碼由3部分組成:
第一個是公司前綴。 第二個是項目參考。
第三位是校驗位。
在此示例中,公司前綴爲0601040.前導零不在此問題的範圍內。
項目引用是一個數字範圍,其大小取決於公司前綴中的數字位數。在這個例子中,我們在公司前綴中有6位數字(不包括前導零)和1位數字,用於保留5位數字作爲項目引用。這會使項目的參考範圍爲0到99999.您需要查找該範圍內未使用的數字。
校驗位使用UPC代碼的其他11位計算: http://www.gs1.org/how-calculate-check-digit-manually
除非你需要存儲無效的UPC代碼,因爲您從外部系統接受不良數據有優勢,存儲公司前綴和項目作爲參考表中不同的領域,並使得UPC索引持久計算字段:
-- Function to output UPC code based on Company Prefix and Item Reference:
CREATE FUNCTION [dbo].[calc_UPC]
(@company_prefix varchar(10), @item_reference int)
RETURNS char(12)
WITH SCHEMABINDING
AS
BEGIN
declare
@upc char(12),
@checkdigit int
if SUBSTRING(@company_prefix, 1, 1) = 0
begin
set @upc = substring(@company_prefix, 2, 10) + right('000000000000' + ltrim(str(@item_reference)), 12 - len(@company_prefix))
set @checkdigit = (1000 - (
convert(int, substring(@upc, 1, 1)) * 3 +
convert(int, substring(@upc, 2, 1)) * 1 +
convert(int, substring(@upc, 3, 1)) * 3 +
convert(int, substring(@upc, 4, 1)) * 1 +
convert(int, substring(@upc, 5, 1)) * 3 +
convert(int, substring(@upc, 6, 1)) * 1 +
convert(int, substring(@upc, 7, 1)) * 3 +
convert(int, substring(@upc, 8, 1)) * 1 +
convert(int, substring(@upc, 9, 1)) * 3 +
convert(int, substring(@upc, 10, 1)) * 1 +
convert(int, substring(@upc, 11, 1)) * 3)) % 10
set @upc = rtrim(@upc) + ltrim(str(@checkdigit))
end
return @upc
END
GO
-- Example Table of products:
CREATE TABLE [dbo].[Product](
[product_id] [int] IDENTITY(1,1) NOT NULL,
[company_prefix] [varchar](10) NULL,
[item_reference] [int] NULL,
[upc] AS ([dbo].[calc_UPC]([company_prefix],[item_reference])) PERSISTED,
CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED
(
[product_id] ASC
))
ALTER TABLE [dbo].[Product] WITH CHECK ADD CONSTRAINT [item_reference_greater_equal_zero] CHECK (([item_reference]>=(0)))
GO
ALTER TABLE [dbo].[Product] CHECK CONSTRAINT [item_reference_greater_equal_zero]
GO
-- Existing records with UPC codes:
insert product (company_prefix, item_reference) values ('0601040', 3)
insert product (company_prefix, item_reference) values ('0601040', 5)
-- Example of 4 new products without UPC codes
insert product DEFAULT VALUES
insert product DEFAULT VALUES
insert product DEFAULT VALUES
insert product DEFAULT VALUES
GO
-- Next we need a table of all possible item references.
-- This is the best implementation I have found for generating numbers:
--Creates a table of sequential numbers, useful for all sorts of things
--Created 08/26/05 by Oskar Austegard from article at
--http://msdn.microsoft.com/library/en-us/dnsqlpro03/html/sp03k1.asp
--Limits: @Min and @Max must be between -2147483647 and 2147483647, including.
--If @Max <= @Min, only a single record with @Min is created
CREATE FUNCTION [dbo].[NumberTable] (@Min int, @Max int)
RETURNS @T TABLE (Number int NOT NULL PRIMARY KEY)
AS
BEGIN
-- Seed the table with the min value
INSERT @T VALUES (@Min)
--Loop until all the rows are created, inserting ever more records for each iteration (1, 2, 4, etc)
WHILE @@ROWCOUNT > 0
BEGIN
INSERT @T
--Get the next values by adding the current max - start value + 1 to each existing number
--need to calculate increment value first to avoid arithmetic overflow near limits of int
SELECT t.Number + (x.MaxNumber - @Min + 1)
FROM @T t
CROSS JOIN (SELECT MaxNumber = MAX(Number) FROM @T) x --Current max
WHERE
--Do not exceed the Max - shift the increment to the right side to take advantage of index
t.Number <= @Max - (x.MaxNumber - @Min + 1)
END
RETURN
END
GO
-- For 10,000 numbers the performance of this function is good,
-- but when the range is known I prefer the performance I get with a static table:
-- Create a table of numbers between 0 and 99999
CREATE table Numbers (number int)
insert Numbers (number)
select n.Number
from dbo.NumberTable(0, 99999) n
-- Now we can easily assign UPC codes using the available item reference values in your Company Prefix in a single update:
declare @company_prefix varchar(10)
set @company_prefix = '0601040' -- The function requires the leading zero
update
p
set
item_reference = n.number,
company_prefix = @company_prefix
from
(
select
p.product_id,
ROW_NUMBER() OVER (order by product_id) [row]
from
dbo.product p
where
p.company_prefix is null
) u
inner join dbo.product p on p.product_id = u.product_id
inner join
(
select
s.Number,
ROW_NUMBER() over (order by s.Number) [row]
from
(
select n.Number from
(
select
n.Number
from
dbo.Numbers n --Table(@sequence, @size - 1) n
left outer join dbo.Product p
on p.company_prefix = @company_prefix
and n.Number = p.item_reference
where
p.product_id is null
) n
) s
) n on n.[row] = u.[row]
GO
select * from product
使用這種方法,你不必擔心作廢的支票數字,你可以輕鬆地分配UPC代碼,以新產品從您的GS1分配的UCC塊。這也使得從新的公司前綴開始分配UPC代碼變得很容易。您可以用相同的方法支持EAN13代碼,只需對函數進行小改動:
CREATE FUNCTION [dbo].[calc_EAN13]
(@company_prefix varchar(10), @item_reference int)
RETURNS char(13)
WITH SCHEMABINDING
AS
BEGIN
declare
@ean13 char(13),
@checkdigit int
set @ean13 = @company_prefix
set @ean13 = @company_prefix + right('0000000000000' + ltrim(str(@item_reference)), 12 - len(@company_prefix))
set @checkdigit = (1000 - (
convert(int, substring(@ean13, 1, 1)) * 1 +
convert(int, substring(@ean13, 2, 1)) * 3 +
convert(int, substring(@ean13, 3, 1)) * 1 +
convert(int, substring(@ean13, 4, 1)) * 3 +
convert(int, substring(@ean13, 5, 1)) * 1 +
convert(int, substring(@ean13, 6, 1)) * 3 +
convert(int, substring(@ean13, 7, 1)) * 1 +
convert(int, substring(@ean13, 8, 1)) * 3 +
convert(int, substring(@ean13, 9, 1)) * 1 +
convert(int, substring(@ean13, 10, 1)) * 3 +
convert(int, substring(@ean13, 11, 1)) * 1 +
convert(int, substring(@ean13, 12, 1)) * 3)) % 10
set @ean13 = rtrim(@ean13) + ltrim(str(@checkdigit))
return @ean13
END
GO
什麼樣的「SQL」? MSSQL,MySQL,PostgreSQL等? – 2012-01-11 21:14:58
SQL Server 2010 – user988265 2012-01-11 21:16:37
@ user988265 - 你的意思是SQL Server 2012,又名「Denali」? – Lamak 2012-01-11 21:35:29