Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL自定义单位转换_Sql_Sql Server - Fatal编程技术网

SQL自定义单位转换

SQL自定义单位转换,sql,sql-server,Sql,Sql Server,我正在寻找SQL中自定义单位转换的解决方案,我的公司使用的数据库是Microsoft SQL server,我需要编写一个SQL来返回基于单位转换表的转换系数 说: 单位换算表: itemid | vendorid | unit1id | unit2id | quantity1 | quantity2 1001 5000 10 500 1000 1 1001 5000 500 305 1 5 问题: 如果我有10盒鸡翅,以克计的期末存货是多少 如何编写此sql以返回转换因子 提前谢谢现在这

我正在寻找SQL中自定义单位转换的解决方案,我的公司使用的数据库是Microsoft SQL server,我需要编写一个SQL来返回基于单位转换表的转换系数

说:

单位换算表:

itemid | vendorid | unit1id | unit2id | quantity1 | quantity2

1001 5000 10 500 1000 1

1001 5000 500 305 1 5
问题: 如果我有10盒鸡翅,以克计的期末存货是多少

如何编写此sql以返回转换因子

提前谢谢

现在这是个棘手的问题。看起来您需要一个递归选择,或者一个光标来解决它。基本上,您要做的是从单位转换表中进行选择,其中itemid=@desiredId和vendorid=@desiredVendor和unit2id=@finalUnitId。然后,您将希望运行相同的查询,但其中unit2id=unit1id来自刚刚运行的查询-直到unit1id=@originalUnitId。始终保持一个运行的转换系数

因此,从以下内容开始: 声明@factor float 设置@factor=0 从unitconversion中选择unit1id、quantity1、quantity2,其中itemid=1001,vendorid=5000,unit2id=305 设置@factor=@factor+quantity1/数量2

然后,您需要检查从上面选择的unit1id是否等于您希望最终使用的单位在您的示例中,您要检查unit1id是否为10。如果不是,请再次运行相同的查询,但将unit2id限制为10


这只是我将如何做的粗略概述。这里有一些假设,主要是如果你遵循单元链,前一个单元总是比你要测试的单元小,但我认为这可能足以传达它的要点。这可能最适合作为UDF实现,UDF返回基于产品、供应商、开始和结束单位的因子。我会使用while语句。

我会使用一个转换表并放入所有组合。所以,即使5000克->5公斤->1盒,我也会把克->盒转换。大概是这样的:

create table unit_unit_conv(
   from_unit varchar(10)   not null
  ,to_unit   varchar(10)   not null
  ,rate      decimal(10,6) not null
  ,primary key(from_unit, to_unit)
);

insert into unit_unit_conv values('kilogram', 'kilogram',   1);
insert into unit_unit_conv values('kilogram', 'gram',       1000);
insert into unit_unit_conv values('kilogram', 'box',        0.2);
insert into unit_unit_conv values('gram',     'gram',       1);
insert into unit_unit_conv values('gram',     'kilogram',   0.001);
insert into unit_unit_conv values('gram',     'box',        0.0002);
insert into unit_unit_conv values('box',      'box',        1);
insert into unit_unit_conv values('box',      'kilogram',   5);
insert into unit_unit_conv values('box',      'gram',       5000);
create table items(
   item_id        varchar(10) not null
  ,item_qty       int not null
  ,item_qty_unit  varchar(10)
);

insert into items values('chicken', 5,    'kilogram');
insert into items values('babies',  5000, 'gram');
insert into items values('beef',    1,    'box');
select i.item_id
      ,i.item_qty    as qty_original
      ,item_qty_unit as qty_unit_original
      ,i.item_qty * c.rate as box_qty
  from items          i
  join unit_unit_conv c on(i.item_qty_unit = c.from_unit)
 where c.to_unit = 'box';

+---------+--------------+-------------------+----------+
| item_id | qty_original | qty_unit_original | box_qty  |
+---------+--------------+-------------------+----------+
| chicken |            5 | kilogram          | 1.000000 |
| babies  |         5000 | gram              | 1.000000 |
| beef    |            1 | box               | 1.000000 |
+---------+--------------+-------------------+----------+
所以无论你有什么度量单位,你都可以将它转换成任何单位,方法是将你的数量乘以这个表中的rate列。因此,如果您有这样一个项目表:

create table unit_unit_conv(
   from_unit varchar(10)   not null
  ,to_unit   varchar(10)   not null
  ,rate      decimal(10,6) not null
  ,primary key(from_unit, to_unit)
);

insert into unit_unit_conv values('kilogram', 'kilogram',   1);
insert into unit_unit_conv values('kilogram', 'gram',       1000);
insert into unit_unit_conv values('kilogram', 'box',        0.2);
insert into unit_unit_conv values('gram',     'gram',       1);
insert into unit_unit_conv values('gram',     'kilogram',   0.001);
insert into unit_unit_conv values('gram',     'box',        0.0002);
insert into unit_unit_conv values('box',      'box',        1);
insert into unit_unit_conv values('box',      'kilogram',   5);
insert into unit_unit_conv values('box',      'gram',       5000);
create table items(
   item_id        varchar(10) not null
  ,item_qty       int not null
  ,item_qty_unit  varchar(10)
);

insert into items values('chicken', 5,    'kilogram');
insert into items values('babies',  5000, 'gram');
insert into items values('beef',    1,    'box');
select i.item_id
      ,i.item_qty    as qty_original
      ,item_qty_unit as qty_unit_original
      ,i.item_qty * c.rate as box_qty
  from items          i
  join unit_unit_conv c on(i.item_qty_unit = c.from_unit)
 where c.to_unit = 'box';

+---------+--------------+-------------------+----------+
| item_id | qty_original | qty_unit_original | box_qty  |
+---------+--------------+-------------------+----------+
| chicken |            5 | kilogram          | 1.000000 |
| babies  |         5000 | gram              | 1.000000 |
| beef    |            1 | box               | 1.000000 |
+---------+--------------+-------------------+----------+
…如果要将所有内容转换为方框,则可以按如下方式查询数据:

create table unit_unit_conv(
   from_unit varchar(10)   not null
  ,to_unit   varchar(10)   not null
  ,rate      decimal(10,6) not null
  ,primary key(from_unit, to_unit)
);

insert into unit_unit_conv values('kilogram', 'kilogram',   1);
insert into unit_unit_conv values('kilogram', 'gram',       1000);
insert into unit_unit_conv values('kilogram', 'box',        0.2);
insert into unit_unit_conv values('gram',     'gram',       1);
insert into unit_unit_conv values('gram',     'kilogram',   0.001);
insert into unit_unit_conv values('gram',     'box',        0.0002);
insert into unit_unit_conv values('box',      'box',        1);
insert into unit_unit_conv values('box',      'kilogram',   5);
insert into unit_unit_conv values('box',      'gram',       5000);
create table items(
   item_id        varchar(10) not null
  ,item_qty       int not null
  ,item_qty_unit  varchar(10)
);

insert into items values('chicken', 5,    'kilogram');
insert into items values('babies',  5000, 'gram');
insert into items values('beef',    1,    'box');
select i.item_id
      ,i.item_qty    as qty_original
      ,item_qty_unit as qty_unit_original
      ,i.item_qty * c.rate as box_qty
  from items          i
  join unit_unit_conv c on(i.item_qty_unit = c.from_unit)
 where c.to_unit = 'box';

+---------+--------------+-------------------+----------+
| item_id | qty_original | qty_unit_original | box_qty  |
+---------+--------------+-------------------+----------+
| chicken |            5 | kilogram          | 1.000000 |
| babies  |         5000 | gram              | 1.000000 |
| beef    |            1 | box               | 1.000000 |
+---------+--------------+-------------------+----------+

我认为一个递归表可以找到从所需的from单元到所需的to单元的路径,这是最好的。类似这样的假设是,如果有路径a->b->c,那么数据库中也有路径c->b->a。如果没有,可以修改为搜索两个方向

select  1001 as itemID
        ,5000 as vendorID
        ,10 as fromUnit
        ,500 as toUnit
        ,cast(1000 as float) as fromQuantity
        ,cast(1 as float) as toQuantity
into #conversionTable
union
select  1001
        ,5000
        ,500
        ,305
        ,1
        ,5
union
select 1001
        ,5000
        ,305
        ,500
        ,5
        ,1
union
select  1001
        ,5000
        ,500
        ,10
        ,1
        ,1000

declare @fromUnit int
        ,@toUnit int
        ,@input int
set @fromUnit = 305 --box
set @toUnit =  10 --gram
set @input = 10

;with recursiveTable as
(
    select  0 as LevelNum
            ,ct.fromUnit
            ,ct.toUnit
            ,ct.toQuantity / ct.fromQuantity as multiplicationFactor
    from #conversionTable ct
    where   ct.fromUnit = @fromUnit

    union all

    select  LevelNum + 1
            ,rt.fromUnit
            ,ct.toUnit
            ,rt.multiplicationFactor * (ct.toQuantity / ct.fromQuantity)
    from #conversionTable ct
    inner join recursiveTable rt on rt.toUnit = ct.fromUnit
)

select @input * r.multiplicationFactor
from
(
    select top 1 * from recursiveTable 
    where (fromUnit = @fromUnit
    and toUnit = @toUnit)
) r

以下解决方案在SQL server 2012上进行了测试。为了减少页面上的代码大小,我只提供质量测量值,因为这些测量值已经过测试并正常工作

CREATE TABLE [Measurement type]
(
   [Type ID] INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
   [Type Name] NVARCHAR(30) NOT NULL
)

CREATE TABLE [Measurement unit]
(
   [Unit ID] INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
   [Type ID] INT REFERENCES [Measurement type]([Type ID]) NOT NULL,
   [Unit name] NVARCHAR(30) NOT NULL,
   [Unit symbol] NVARCHAR(10) NOT NULL
)

/* Use both multiplier and divizor to reduce rounding errors */
CREATE TABLE [Measurement conversions]
(
   [Type ID] INT NOT NULL REFERENCES [Measurement type]([Type ID]),
   [From Unit ID] INT NOT NULL REFERENCES [Measurement unit]([Unit ID]),
   [To Unit ID] INT NOT NULL REFERENCES [Measurement unit]([Unit ID]),
   [From Unit Offset] FLOAT NOT NULL DEFAULT(0),
   [Multiplier] FLOAT NOT NULL DEFAULT(1),
   [Divizor] FLOAT NOT NULL DEFAULT(1),
   [To Unit Offset] FLOAT NOT NULL DEFAULT(0),
   PRIMARY KEY ([Type ID], [From Unit ID], [To Unit ID])
)

INSERT INTO [Measurement type]([Type ID], [Type Name]) VALUES(4, 'Mass')

INSERT INTO [Measurement unit]([Unit ID], [Type ID], [Unit name], [Unit symbol])
VALUES (28, 4, 'Milligram', 'mg'), (29, 4, 'Gram', 'g'),
       (30, 4, 'Kilogram', 'kg'), (31, 4, 'Tonne', 't'),
       (32, 4, 'Ounce', 'oz'), (33, 4, 'Pound', 'lb'),
       (34, 4, 'Stone', 's'), (35, 4, 'hundred weight', 'cwt'),
       (36, 4, 'UK long ton', 'ton')

INSERT INTO [Measurement conversions]([Type ID], [From Unit ID], [To Unit ID], [Multiplier], [Divizor])
VALUES (4, 28, 29, 1, 1000), (4, 28, 30, 1, 1000000), (4, 28, 31, 1, 1000000000),
       (4, 28, 32, 1, 28350), (4, 32, 33, 1, 16), (4, 32, 34, 1, 224),
       (4, 32, 35, 1, 50802345), (4, 32, 36, 1, 35840)

INSERT INTO [Measurement conversions]([Type ID], [From Unit ID], [To Unit ID], [From Unit Offset], [Multiplier], [Divizor], [To Unit Offset])
SELECT DISTINCT [Measurement Conversions].[Type ID],
                [Measurement Conversions].[To Unit ID],
                [Measurement Conversions].[From Unit ID],
                -[Measurement Conversions].[To Unit Offset],
                [Measurement Conversions].[Divizor],
                [Measurement Conversions].[Multiplier],
                -[Measurement Conversions].[From Unit Offset]
FROM [Measurement Conversions]
-- LEFT JOIN Used to assure that we dont try to insert already existing keys.
LEFT JOIN [Measurement conversions] AS [Existing]
ON [Measurement Conversions].[From Unit ID] = [Existing].[To Unit ID] AND [Measurement Conversions].[To Unit ID] = [Existing].[From Unit ID]
WHERE [Existing].[Type ID] IS NULL
运行以下查询,直到它影响0行

INSERT INTO [Measurement conversions]([Type ID], [From Unit ID], [To Unit ID], [From Unit Offset], [Multiplier], [Divizor], [To Unit Offset])
SELECT DISTINCT [From].[Type ID],
                [From].[To Unit ID] AS [From Unit ID],
                [To].[To Unit ID],
                -[From].[To Unit Offset] + (([To].[From Unit Offset]) * [From].[Multiplier] / [From].Divizor) AS [From Unit Offset],
                [From].[Divizor] * [To].[Multiplier] AS Multiplier,
                [From].[Multiplier] * [To].[Divizor] AS Divizor,
                [To].[To Unit Offset] - (([From].[From Unit Offset]) * [To].[Multiplier] / [To].Divizor) AS [To Unit Offset]
FROM [Measurement conversions] AS [From]
CROSS JOIN [Measurement conversions] AS [To]
-- LEFT JOIN Used to assure that we dont try to insert already existing keys.
LEFT JOIN [Measurement conversions] AS [Existing]
ON [From].[To Unit ID] = [Existing].[From Unit ID] AND [To].[To Unit ID] = [Existing].[To Unit ID]
WHERE [Existing].[Type ID] IS NULL
      AND [From].[Type ID] = [To].[Type ID]
      AND [From].[To Unit ID] <> [To].[To Unit ID]
      AND [From].[From Unit ID] = [To].[From Unit ID]

您能否重新格式化您的问题,目前尚不清楚哪些内容需要转换为哪些内容。你想要的最终答案是什么?10个整盒的鸡翅有多少克?你能澄清一下:每排有2个单位/数量对吗?这些是开始和结束数量,还是从和到单位?我不清楚您要转换哪个项目?我必须在这方面学习一下,因为我刚刚开始SQL之旅。感谢您的回复,但是我无法对数据库进行任何更改,因此这是我唯一可以使用的。