Chuyển dữ liệu chữ tượng hình từ một VARCHAR sang hai INT


7

VẤN ĐỀ

Bảng nơi dữ liệu được ghi là

CREATE TABLE [dbo].[Almoxarifado](
    [idAlmoxarifado] [varchar](20) NOT NULL,
    [tipoAlmoxarifadoId] [varchar](30) NOT NULL,
    [entidadeId] [bigint] NOT NULL,
    [dtInclusao] [smalldatetime] NOT NULL,
    [dtUltimaAlteracao] [smalldatetime] NULL,
    [descricao] [varchar](255) NOT NULL,
    [terceiro] [bit] NOT NULL
) ON [PRIMARY]

Và đây là một SELECT TOP 10 *ví dụ (bảng có hơn 1 triệu mục):

Chọn kết quả

Như bạn có thể thấy, idAlmoxarifadotrường đang lưu trữ dữ liệu phân cấp không có mối quan hệ phân cấp như hầu hết các bảng phân cấp có.

Bây giờ tôi muốn đưa dữ liệu này vào một bảng phân cấp thông thường:

CREATE TABLE [dbo].[Almoxarifado2](
    [idMaster] [bigint] IDENTITY(1,1) NOT NULL,
    [idAlmoxarifado] [int] NOT NULL,
    [idAlmoxPai] [int] NOT NULL DEFAULT ((0)),
    [entidadeId] [bigint] NOT NULL,
    [tipoAlmoxarifadoId] [varchar](30) NOT NULL 
    [dtInclusao] [datetime] NULL DEFAULT (getdate()),
    [dtUltimaAlteracao] [datetime] NULL,
    [descricao] [varchar](255) NOT NULL,
    [terceiro] [bit] NULL DEFAULT ((0)),
    PRIMARY KEY ([idMaster])
)

Trên bàn này, tôi sẽ có một mối quan hệ cha-con bình thường trong đó "cha" của một lĩnh vực nhất định sẽ luôn là idMasterphóng viên (trừ khi nó ở cấp độ đầu tiên của chuỗi phân cấp; sau đó sẽ là "cha" 0).

Vì vậy, nếu chúng ta tuân theo cùng thứ tự hiển thị trên hình ảnh trên, chúng ta nên có (sau khi chèn dữ liệu được chuyển đổi trên bảng mới):

nhập mô tả hình ảnh ở đây

CÂU HỎI

Làm thế nào tôi có thể thực hiện chuyển vị này là một cách an toàn và không gây đau đớn vì bảng gốc có hơn 1 mi mục?

NHỮNG QUY ĐỊNH

Không có giới hạn về số lượng cấp cao nhất có thể tồn tại; Không phải cấp độ trẻ em. Ý tưởng của chúng tôi là làm việc với mặt nạ để làm cho dữ liệu trở nên hữu ích trên ứng dụng của chúng tôi (chúng tôi làm việc với Máy tính cầm tay Motorola; kiểm tra MC45 và MC3190). Hãy nói rằng khách hàng mua giải pháp của chúng tôi có một số Kho nơi anh ta lưu trữ các sản phẩm của mình. Trong trường hợp này, anh ta sẽ có thể xác định mặt nạ (giả sử 9,99,99,999 hoặc 9,9,99,99,99,99) và hệ thống của chúng tôi sẽ phải sử dụng mặt nạ này để cho phép anh ta đăng ký kho của mình ở các cấp đó.

Vì vậy, về cơ bản bạn có thể nói rằng hệ thống của chúng tôi được tập trung vào hậu cần theo cách thức.

Trong đó cấp 1 có thể là "NY South Warehouse", "Phòng số 2" thứ 2, "Hành lang A" thứ 3, "Tủ ​​khóa 2" thứ 4 và "Kệ 3" thứ 5.

Câu trả lời:


10

Vì dữ liệu của bạn trông hơi giống phân cấp. Tôi nghĩ về việc sử dụng nó. Các phiên bản ban đầu không có quy mô lên tới 1 triệu hàng, tuy nhiên một vài lựa chọn lập chỉ mục trên bảng tạm thời chính đã giúp ích. Tuy nhiên, các vấn đề cũng có thể là do dữ liệu thử nghiệm của tôi, vì vậy bạn có thể cho tôi biết thêm một chút về hệ thống phân cấp của bạn không? Ví dụ, có bao nhiêu cha mẹ cấp cao nhất, trung bình có bao nhiêu cấp độ, mỗi cấp độ có bao nhiêu con?

Trong khi đó, đây là một phiên bản để bạn có thể xem qua nó và xem liệu hierarchyIdcó thể làm việc cho bạn không.

Ý tưởng cơ bản là tạo một bảng tạm thời với các id gốc được chuyển đổi thành hierarchyIds, sau đó đi theo cấu trúc phân cấp để tìm ra dòng dõi. Bảng tạm thời này (có thể là vĩnh viễn) sau đó có thể được sử dụng để di chuyển:

USE tempdb
GO

SET NOCOUNT ON
GO

IF OBJECT_ID('[dbo].[Almoxarifado]') IS NOT NULL DROP TABLE [dbo].[Almoxarifado]
IF OBJECT_ID('[dbo].[Almoxarifado2]') IS NOT NULL DROP TABLE [dbo].[Almoxarifado2]
GO


CREATE TABLE [dbo].[Almoxarifado](
    [idAlmoxarifado] [varchar](20) NOT NULL,
    [tipoAlmoxarifadoId] [varchar](30) NOT NULL,
    [entidadeId] [bigint] NOT NULL,
    [dtInclusao] [smalldatetime] NOT NULL,
    [dtUltimaAlteracao] [smalldatetime] NULL,
    [descricao] [varchar](255) NOT NULL,
    [terceiro] [bit] NOT NULL
) ON [PRIMARY]
GO



CREATE TABLE [dbo].[Almoxarifado2](
    [idMaster] [bigint] IDENTITY(1,1) NOT NULL,
    [idAlmoxarifado] [int] NOT NULL,
    [idAlmoxPai] [int] NOT NULL DEFAULT ((0)),
    [entidadeId] [bigint] NOT NULL,
    [tipoAlmoxarifadoId] [varchar](30) NOT NULL ,
    [dtInclusao] [datetime] NULL DEFAULT (getdate()),
    [dtUltimaAlteracao] [datetime] NULL,
    [descricao] [varchar](255) NOT NULL,
    [terceiro] [bit] NULL DEFAULT ((0)),
    PRIMARY KEY ([idMaster])
)
GO

/*
-- Test data
INSERT INTO [dbo].[Almoxarifado] ( idAlmoxarifado, tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro )
VALUES
    ( '1', 'TESTE', 12, '29 Apr 2016', NULL, '0000000', 0 ),
    ( '1.1', 'TESTE', 12, '29 Apr 2016', NULL, '0000001', 0 ),
    ( '1.1.01', 'TESTE', 12, '29 Apr 2016', NULL, '0000002', 0 ),
    ( '1.1.01.01', 'TESTE', 12, '29 Apr 2016', NULL, '0000003', 0 ),
    ( '1.1.01.01.001', 'TESTE', 12, '29 Apr 2016', NULL, '0000004', 0 ),

    ( '1.1.01.01.002', 'TESTE', 12, '29 Apr 2016', NULL, '0000005', 0 ),
    ( '1.1.01.01.003', 'TESTE', 12, '29 Apr 2016', NULL, '0000006', 0 ),
    ( '1.1.01.01.004', 'TESTE', 12, '29 Apr 2016', NULL, '0000007', 0 ),
    ( '1.1.01.01.005', 'TESTE', 12, '29 Apr 2016', NULL, '0000008', 0 ),
    ( '1.1.01.01.006', 'TESTE', 12, '29 Apr 2016', NULL, '0000009', 0 )
GO
*/

-- Add 10 parent levels
INSERT INTO [dbo].[Almoxarifado] ( idAlmoxarifado, tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro )
VALUES
    ( '1', 'TESTE', 1, '1 Jan 2016', NULL, '00000001', 0 ),
    ( '2', 'TESTE', 1, '1 Feb 2016', NULL, '00000002', 0 ),
    ( '3', 'TESTE', 1, '1 Mar 2016', NULL, '00000003', 0 ),
    ( '4', 'TESTE', 1, '1 Apr 2016', NULL, '00000004', 0 ),
    ( '5', 'TESTE', 1, '1 May 2016', NULL, '00000005', 0 ),
    ( '6', 'TESTE', 1, '1 Jun 2016', NULL, '00000006', 0 ),
    ( '7', 'TESTE', 1, '1 Jul 2016', NULL, '00000007', 0 ),
    ( '8', 'TESTE', 1, '1 Aug 2016', NULL, '00000008', 0 ),
    ( '9', 'TESTE', 1, '1 Sep 2016', NULL, '00000008', 0 ),
    ( '10', 'TESTE', 1, '1 Oct 2016', NULL, '00000010', 0 )


-- For each parent, add 3 sublevels
INSERT INTO [dbo].[Almoxarifado] ( idAlmoxarifado, tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro )
SELECT 
    idAlmoxarifado + '.' + CAST( x.y AS VARCHAR(10) ),
    tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro
FROM [dbo].[Almoxarifado] a
    CROSS JOIN ( SELECT TOP 5 idAlmoxarifado y FROM [dbo].[Almoxarifado] ) x


-- add n sublevels
INSERT INTO [dbo].[Almoxarifado] ( idAlmoxarifado, tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro )
SELECT 
    idAlmoxarifado + '.0' + CAST( x.y AS VARCHAR(10) ),
    tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro
FROM [dbo].[Almoxarifado] a
    CROSS JOIN ( SELECT TOP 8 idAlmoxarifado y FROM [dbo].[Almoxarifado] WHERE idAlmoxarifado Not Like '%.%' ) x
WHERE idAlmoxarifado Like '%.%'


-- Add 8 sublevels
INSERT INTO [dbo].[Almoxarifado] ( idAlmoxarifado, tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro )
SELECT 
    idAlmoxarifado + '.0' + CAST( x.y AS VARCHAR(10) ),
    tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro
FROM [dbo].[Almoxarifado] a
    CROSS JOIN ( SELECT TOP 13 ROW_NUMBER() OVER( ORDER BY idAlmoxarifado ) y FROM [dbo].[Almoxarifado] ) x
WHERE idAlmoxarifado Like '%.%.%'


-- Add 9 sublevels
INSERT INTO [dbo].[Almoxarifado] ( idAlmoxarifado, tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro )
SELECT 
    idAlmoxarifado + '.0' + CAST( x.y AS VARCHAR(10) ),
    tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro
FROM [dbo].[Almoxarifado] a
    CROSS JOIN ( SELECT TOP 21 ROW_NUMBER() OVER( ORDER BY idAlmoxarifado ) y FROM [dbo].[Almoxarifado] ) x
WHERE idAlmoxarifado Like '%.%.%.%'
GO

INSERT INTO [dbo].[Almoxarifado] ( idAlmoxarifado, tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro )
SELECT 
    idAlmoxarifado + '.0' + CAST( x.y AS VARCHAR(10) ),
    tipoAlmoxarifadoId, entidadeId, dtInclusao, dtUltimaAlteracao, descricao, terceiro
FROM [dbo].[Almoxarifado] a
    CROSS JOIN ( SELECT TOP 9 ROW_NUMBER() OVER( ORDER BY idAlmoxarifado ) y FROM [dbo].[Almoxarifado] ) x
WHERE idAlmoxarifado Like '%.%.%.%.%'
GO



-- Main hierarchyId processing
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp

SELECT
    IDENTITY( INT, 1, 1 ) AS idMaster,
    idAlmoxarifado,
    CAST( '/' + REPLACE( REPLACE( REPLACE( idAlmoxarifado, '.0', '.' ), '.0', '.' ), '.', '/' ) + '/' AS hierarchyid ) hId,
    CAST( '/' + REPLACE( REPLACE( REPLACE( idAlmoxarifado, '.0', '.' ), '.0', '.' ), '.', '/' ) + '/' AS hierarchyid ).ToString() hString,
    CAST( NULL AS INT ) AS idAlmoxarifado2,
    CAST( NULL AS INT ) AS idAlmoxPai

INTO #tmp
FROM [dbo].[Almoxarifado]
GO


-- Index temp table to help with recursive CTE
ALTER TABLE #tmp ADD PRIMARY KEY ( idMaster )
ALTER TABLE #tmp ALTER COLUMN hId hierarchyId NOT NULL
CREATE UNIQUE INDEX _idx ON #tmp ( hId ) INCLUDE ( idAlmoxarifado, hString )
GO


-- Walk the hierarchy
;WITH cte AS (
SELECT 1 AS xlevel, idMaster, idAlmoxarifado, hId, hString, hId.GetLevel() getLevel, 0 AS parentId
FROM #tmp
WHERE hId.GetLevel() = 1

UNION ALL

SELECT xlevel + 1, t.idMaster, t.idAlmoxarifado, t.hId, t.hString, t.hId.GetLevel() getLevel, c.idMaster AS parentId
FROM cte c
    INNER JOIN #tmp t ON c.hId  = t.hId.GetAncestor(1)
)
UPDATE t
SET 
    -- Parse out the individual node, by taking its parent and stuffing it in front
    t.idAlmoxarifado2 = CAST( REPLACE( STUFF( c.hString, 1, LEN(c.hId.GetAncestor(1).ToString()), '' ), '/', '' ) AS INT ),
    t.idAlmoxPai = parentId
FROM cte c
    INNER JOIN #tmp t ON c.idMaster = T.idMaster


-- Check results
SELECT *
FROM #tmp

Toàn bộ tập lệnh này (bao gồm tạo dữ liệu thử nghiệm) chỉ chạy trong vài phút trên máy tính xách tay của tôi.


5

Thêm một cột vào dbo.Almoxarifado2đó sẽ giữ giá trị ban đầu của idAlmoxarifado.

Thêm tất cả các hàng từ dbo.Almoxarifadovà sau đó sử dụng idAlmoxarifadoOrgđể cập nhật idAlmoxPaivới giá trị của idMasterhàng cha.

Mã với một số ý kiến:

-- Add a column to store original idAlmoxarifado
alter table dbo.Almoxarifado2 
    add idAlmoxarifadoOrg varchar(20) not null;

go

-- Add all rows to Almoxarifado2 with 0 to idAlmoxPai 
-- and the rightmost number of idAlmoxarifado to idAlmoxarifado.
-- Original value of idAlmoxarifado goes to idAlmoxarifadoOrg
insert into dbo.Almoxarifado2(idAlmoxarifado, idAlmoxPai, entidadeId, tipoAlmoxarifadoId, dtInclusao, dtUltimaAlteracao, descricao, terceiro, idAlmoxarifadoOrg)
select right(A.idAlmoxarifado, charindex('.', reverse('.'+A.idAlmoxarifado)) - 1), 0, A.entidadeId, A.tipoAlmoxarifadoId, A.dtInclusao, A.dtUltimaAlteracao, A.descricao, A.terceiro, A.idAlmoxarifado
from dbo.Almoxarifado as A;

go

-- Update idAlmoxPai with the parent idMaster
-- Don't update root nodes
update A
set idAlmoxPai = P.idMaster
from dbo.Almoxarifado2 as A
  inner join dbo.Almoxarifado2 as P
    on P.idAlmoxarifadoOrg = left(A.idAlmoxarifadoOrg, len(A.idAlmoxarifadoOrg) - charindex('.', reverse(A.idAlmoxarifadoOrg)))
where charindex('.', A.idAlmoxarifadoOrg) > 0;

go

-- Cleanup
alter table dbo.Almoxarifado2 drop column idAlmoxarifadoOrg;

Một số phần có thể làm với một số thông tin thêm.

Điều này right(A.idAlmoxarifado, charindex('.', reverse('.'+A.idAlmoxarifado)) - 1)trích xuất số cuối cùng trong idAlmoxarifado. Vậy 1.1.10sẽ cho bạn a 10.

Và phần này left(A.idAlmoxarifado, len(A.idAlmoxarifado) - charindex('.', reverse(A.idAlmoxarifado)))trả về tất cả trừ số cuối cùng. Vì 1.1.10nó sẽ trở lại 1.1.

Tôi đã xấu hổ lấy trộm dữ liệu thử nghiệm được tạo bởi wBob (cảm ơn và đánh giá cao) và phát hiện ra rằng phiên bản này nhanh hơn trên máy của tôi. Tôi sử dụng một máy tính xách tay 2 lõi thực sự cổ xưa cho các thử nghiệm để kết quả có thể khác nhau trên một máy chủ thực sự. Dù sao đi nữa, đối với tôi mất 3 phút để thực thi mã bằng wBob và giải pháp của tôi là khoảng 20 giây.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.