利用datalength來補上空白,再組出需要的固定長度字串
記錄一下同事阿紅哥提供的組出想要的字串長度,如下,
--資料1
declare @value1 varchar(20);
set @value1 = '這是亂馬客~~~';
--資料2
declare @value2 varchar(20);
set @value2 = '資料2開頭';
--要長度90的字串
declare @fixedLen int;
set @fixedLen = 30;
select @value1 + SPACE(@fixedLen-datalength(@value1)) + ']' as result
union
select @value2 + SPACE(@fixedLen-datalength(@value2)) + ']';
做法很簡單,就是補上剩餘的空白。
所以它有以下幾個限制,
1.需要的長度要大於原資料的長度
2.資料型態要為VARCHAR,這樣 datalength 才算得準。
所以我們可以包一個Function出來如下,
IF OBJECT_ID (N'dbo.ufn_GetFixedStr') IS NOT NULL
DROP FUNCTION dbo.ufn_GetFixedStr
GO
CREATE FUNCTION dbo.ufn_GetFixedStr (@value varchar(8000), @fixedLen int)
RETURNS varchar(8000)
AS
BEGIN
declare @result varchar(8000);
set @result = @value + SPACE(@fixedLen-datalength(@value));
RETURN @result;
END
GO
這樣的東西可以用在像那種 三聯式報表 的應用。
所以可以產生報表的明細資料出來,如下,
use tempdb
go
CREATE TABLE Product
(
ItemNo VARCHAR(30),
ItemName NVARCHAR(90),
Price MONEY)
GO
CREATE TABLE OrderDetail
(id INT,
ItemNo VARCHAR(30),
Qty INT )
GO
CREATE TABLE [Order]
(
id INT,
CustName NVARCHAR(30)
)
GO
delete from Product;
INSERT INTO Product( ItemNo, Price, ItemName)
VALUES( '0001', 100, N'大頭狗');
INSERT INTO Product( ItemNo, Price, ItemName)
VALUES( '0002', 200, N'Surface Pro 3');
INSERT INTO Product( ItemNo, Price, ItemName)
VALUES( '0003', 300, N'自拍神器');
delete from [Order];
INSERT INTO [Order](id, CustName)
VALUES( 1, N'亂馬客' );
INSERT INTO [Order](id, CustName)
VALUES( 2, N'Katusa' );
delete from OrderDetail;
INSERT INTO OrderDetail(id, ItemNo, Qty)
VALUES( 1, '0001', 1);
INSERT INTO OrderDetail(id, ItemNo, Qty)
VALUES( 1, '0002', 2);
INSERT INTO OrderDetail(id, ItemNo, Qty)
VALUES( 1, '0003', 4);
INSERT INTO OrderDetail(id, ItemNo, Qty)
VALUES( 2, '0001', 1);
INSERT INTO OrderDetail(id, ItemNo, Qty)
VALUES( 2, '0002', 2);
INSERT INTO OrderDetail(id, ItemNo, Qty)
VALUES( 2, '0003', 5);
IF OBJECT_ID (N'dbo.ufn_GetFixedStr') IS NOT NULL
DROP FUNCTION dbo.ufn_GetFixedStr
GO
CREATE FUNCTION dbo.ufn_GetFixedStr (@value varchar(8000), @fixedLen int)
RETURNS varchar(8000)
AS
BEGIN
declare @result varchar(8000);
set @result = @value + SPACE(@fixedLen-datalength(@value));
RETURN @result;
END
GO
;
WITH cte_Orders
AS
(
SELECT o.id, o.CustName, p.ItemNo, p.Price, p.ItemName , od.Qty, od.Qty * p.Price AS Total
, SUM(od.Qty * p.Price) OVER (PARTITION BY o.id) AS OrderTotal
FROM [Order] o INNER JOIN OrderDetail od
ON o.id = od.id
INNER JOIN Product p
ON p.ItemNo = od.ItemNo
)
SELECT DISTINCT
id ,
CustName ,
OrderTotal,
STUFF(( SELECT ',' + dbo.ufn_GetFixedStr(ItemNo , 10)
+ dbo.ufn_GetFixedStr(cast(ItemName as varchar(30)), 30)
+ dbo.ufn_GetFixedStr(cast(Qty as varchar(10)), 10)
+ dbo.ufn_GetFixedStr(cast(Price as varchar(10)), 10)
+ dbo.ufn_GetFixedStr(cast(Total as varchar(13)), 10)
FROM cte_Orders b
WHERE a.id = b.id
FOR
XML PATH('')
), 1, 1, '') AS [details]
FROM cte_Orders a;
-- 因為 3 聯式,所以重覆 3個資料出來
WITH cte_Orders
AS
(
SELECT o.id, o.CustName, p.ItemNo, p.Price, p.ItemName , od.Qty, od.Qty * p.Price AS Total
, SUM(od.Qty * p.Price) OVER (PARTITION BY o.id) AS OrderTotal
FROM [Order] o INNER JOIN OrderDetail od
ON o.id = od.id
INNER JOIN Product p
ON p.ItemNo = od.ItemNo
)
, cte_Group
AS
(
SELECT 1 AS GroupNo
UNION ALL
SELECT GroupNo + 1
FROM cte_Group
WHERE GroupNo < 3
)
SELECT o.id, o.CustName, o.OrderTotal, g.GroupNo
, REPLACE(o.details, ',', CHAR(10) + CHAR(13)) AS details
FROM (SELECT DISTINCT
id ,
CustName ,
OrderTotal,
STUFF(( SELECT ',' + dbo.ufn_GetFixedStr(ItemNo , 10)
+ dbo.ufn_GetFixedStr(cast(ItemName as varchar(30)), 30)
+ dbo.ufn_GetFixedStr(cast(Qty as varchar(10)), 10)
+ dbo.ufn_GetFixedStr(cast(Price as varchar(10)), 10)
+ dbo.ufn_GetFixedStr(cast(Total as varchar(13)), 10)
FROM cte_Orders b
WHERE a.id = b.id
FOR
XML PATH('')
), 1, 1, '') AS [details]
FROM cte_Orders a) o
CROSS APPLY cte_Group g;
-- clear testing
-- drop table Product
-- drop table [Order]
-- drop table OrderDetail
Hi,
亂馬客Blog已移到了 「亂馬客 : Re:從零開始的軟體開發生活」
請大家繼續支持 ^_^