我的行数如下:
| Material No | Quantity | Weight | Unit |
--------------------------------------------
| 111-22283/4 | 2 | 53 | kg |
| 123-ABC45/7 | 5 | 41 | g |
| 133-67879/80 | 7 | 31 | g |
| 144-54628 | 1 | 14 | kg |
现在我要产生如下输出:
| Material No | Quantity | Weight | Unit |
--------------------------------------------
| 111-22283 | 2 | 53 | kg |
| 111-22284 | 2 | 53 | kg |
| 123-ABC45 | 5 | 41 | g |
| 123-ABC46 | 5 | 41 | g |
| 123-ABC47 | 5 | 41 | g |
| 133-67879 | 7 | 31 | g |
| 133-67880 | 7 | 31 | g |
| 144-54628 | 1 | 14 | kg |
逻辑:基于材料,我不必拆分行。如果在材料末尾没有'/',则需要将其打散。然后,我们必须在物料编号和编号/之间找到最后一个数字b / w的差。如果它是2
,那么我想要2个不同的行,每个数字都作为物料编号(表示最后一位数字是83/4,那么我希望物料编号以83和84 结尾)。棘手的部分是当我们有89/90时。 /后面将包含2个数字(仅用于10、20等,)。每种物料编号的所有其他列将保持不变。
要实现此目的,当前我们有一个非常大的过程,其中包含大约50-80行代码(找到带有'/'的行,然后分别删除然后找到/的索引,依此类推)。我想知道这是否可以通过简单的查询或很短的过程来完成。
答案 0 :(得分:1)
更新
当MATERIALNO
中的值可以代表一系列值时(作为更新的问题):
DDL
CREATE FUNCTION UFN_STRTOSERIES (@materialNo VARCHAR(80), @qte INT, @weight INT, @unit VARCHAR(50))
RETURNS @result TABLE (
MATERIALNO VARCHAR(80),
QTE INT,
Weight INT,
UNIT VARCHAR(50)
)
AS
BEGIN
DECLARE @base VARCHAR(50) = LEFT(@materialNo,CHARINDEX('/',@materialNo)-1-LEN(RIGHT(@materialNo,LEN(@materialNo)-CHARINDEX('/',@materialNo))));
DECLARE @start INT = CONVERT( INT , RIGHT( LEFT(@materialNo,CHARINDEX('/',@materialNo)-1) , LEN(RIGHT(@materialNo,LEN(@materialNo)-CHARINDEX('/',@materialNo))) ) );
DECLARE @end INT = CONVERT( INT , RIGHT(@materialNo,LEN(@materialNo)-CHARINDEX('/',@materialNo)) );
DECLARE @i INT = @start;
WHILE @i <= @end
BEGIN
INSERT @result
SELECT CONCAT(@base,@i) AS MATERIALNO, @qte, @weight, @unit;
SET @i = @i + 1;
END;
RETURN
END;
CREATE TABLE MATERIALS
(
MATERIALNO VARCHAR(80),
QTE INT,
Weight INT,
UNIT VARCHAR(50)
)
INSERT INTO MATERIALS VALUES
('111-22283/4',2,53,'kg'),
('123-33345/7',5,41,'g' ),
('123-ABC45/7',5,41,'g'),
('133-67879/80',7,31,'g'),
('144-54628',1,14,'kg')
DML
SELECT MATERIALNO,QTE,Weight,UNIT
FROM (
SELECT MATERIALNO,QTE,Weight,UNIT
FROM MATERIALS
WHERE CHARINDEX('/',MATERIALNO) < 1
UNION
SELECT series.MATERIALNO,series.QTE,series.Weight,series.UNIT
FROM MATERIALS m
CROSS APPLY UFN_STRTOSERIES(MATERIALNO,QTE,Weight,UNIT) series
WHERE CHARINDEX('/',m.MATERIALNO) > 1
) base
ORDER BY base.MATERIALNO
旧答案
当MATERIALNO
中的值表示仅两个值时:
UNION
是最简单的答案(然后您必须检查性能):
DDL
CREATE TABLE MATERIALS
(
MATERIALNO VARCHAR(80),
QTE INT,
Weight INT,
UNIT VARCHAR(50)
)
INSERT INTO MATERIALS VALUES
('111-22283/4',2,53,'kg'),
('123-33345/7',5,41,'g' ),
('133-67879/80',7,31,'g'),
('144-54628',1,14,'kg' )
查询
SELECT MATERIALNO,QTE,Weight,UNIT
FROM (
SELECT MATERIALNO,QTE,Weight,UNIT
FROM MATERIALS
WHERE CHARINDEX('/',MATERIALNO) < 1
UNION
SELECT LEFT(MATERIALNO,CHARINDEX('/',MATERIALNO)-1),QTE,Weight,UNIT
FROM MATERIALS
WHERE CHARINDEX('/',MATERIALNO) > 1
UNION
SELECT
CONCAT(LEFT(MATERIALNO,CHARINDEX('/',MATERIALNO)-1-LEN(RIGHT(MATERIALNO,LEN(MATERIALNO)-CHARINDEX('/',MATERIALNO)))),RIGHT(MATERIALNO,LEN(MATERIALNO)-CHARINDEX('/',MATERIALNO))) AS MATERIALNO
,QTE,Weight,UNIT
FROM MATERIALS
WHERE CHARINDEX('/',MATERIALNO) > 1
) BASE
ORDER BY BASE.MATERIALNO
答案 1 :(得分:1)
最具挑战性的部分可能是将material no
拆分为starting
和ending
号。
在那之后,增加数字并连接起来形成材料编号只是一个简单的递归查询。
;with rcte as
(
select MaterialNo,
base, st, en, n = st,
material = convert(varchar(20), base + isnull(convert(varchar(10), st), ''))
from material m
-- get the position of the `/`
cross apply
(
select split = charindex('/', MaterialNo)
) s
-- extract the ending number and convert to integer
cross apply
(
select en = case when split > 0
then convert(int, right(MaterialNo, len(MaterialNo) - split))
end
) en
-- extract the starting number and convert to integer
cross apply
(
select st = case when split > 0
then convert(int, substring(MaterialNo, split - len(en), len(en)))
end
) st
-- extract the base material no for concatenate
cross apply
(
select base = case when split > 0
then left(MaterialNo, split - len(en) - 1)
else MaterialNo
end
) b
union all
select MaterialNo, base, st, en,
n = n + 1,
material = convert(varchar(20), base + convert(varchar(10), n + 1))
from rcte
where n < en
)
select *
from rcte
order by MaterialNo, material
所有这些都是基于这样的假设,即材料号的结尾是纯数字。
注意:如果您有一个计数表,则可以使用它来代替递归cte