이것은 내 첫 번째 게시물이므로 부드럽게 처리하십시오. SSIS 패키지를 구축하여 직장에서 회사 전체에서 실행되는 작업에 대한 정보를 수집합니다. 목표는 서버, 인스턴스, DB, 작업 및 서로의 관계에 대한 정보로 테이블을 채우는 것입니다. 이상적으로는 병합 명령을 사용하여 필요에 따라 업데이트하거나 삽입하지만 현재는 삽입 만합니다. 여기 내 패키지의 개요 (: P 시궁창하십시오에서 당신의 마음을 유지)입니다SSIS의 데이터 흐름 작업에서 쉼표로 구분 된 필드에서 피벗 테이블 채우기
이(새 사용자를위한 하이퍼 링크에 대한 제한 당신이 내 링크에서 "t"의와 + 표시를 교체해야 의미
http://img262.imageshack.us/i/package.jpg/ 첫 번째 데이터 흐름 태스크는 플랫 텍스트 파일에서 확인하기 위해 인스턴스 목록을 가져 와서 레코드 세트에 저장하고 foreach 루프는 각각을 통과하여 원본 연결 관리자의 연결 문자열을 변경합니다. 루프 내부에서 우리는 한 번에 1 개의 인스턴스를 처리하고 있습니다. "프로세스 서버"데이터 흐름 태스크는 서버 이름을 찾아서 목적지 DB에 추가합니다 패키지 변수에 서버 ID 및 이름도 저장됩니다. "프로세스 인스턴스"는 위와 동일하지만 인스턴스 대신 사용됩니다. 그런 다음 "DB 데이터 수집"작업은 해당 패키지 변수를 사용하여 해당 인스턴스에있는 모든 데이터베이스를 외래 키에 대해 위에서 언급 한 패키지 변수가있는 레코드로 삽입합니다. 완료되면 "작업 데이터 수집"작업으로 넘어갑니다 (이 패키지의 최종 작업이되기를 바랍니다). 다음은 마지막 작업의 내용입니다 :
그래서이 작업의 내부 이것이 내가 지금까지 뭘하는지입니다http://img809.imageshack.us/i/dataflow.png/
. 유지 관리 계획 데이터가있는 작업 정보를 수집하는 쿼리를 사용합니다. 다음은 OLE DB 원본에 대한 쿼리입니다.
--WRITTEN BY MAXWELL WALLACE
--THE PURPOSE OF THIS QUERY IS TO COLLECT INFORMATION ABOUT JOBS AND MAINTENANCE PLANS
--RUNNING ON A PARTICULAR INSTANCE. IT COLLECTS NAMES, STATUSES, RUN TIMES AND DATES
--AS WELL AS DATABASES AFFECTED AND MAINTENANCE PLAN NAMES IF APPLICABLE.
SELECT B.NAME AS JOB_NAME, B.CATEGORY_ID,
--RUN_STATUS CODE GETS TRANSLATED INTO ENGLISH
CASE A.RUN_STATUS
WHEN 0 THEN 'Failed'
WHEN 1 THEN 'Succeeded'
WHEN 2 THEN 'Retry'
WHEN 3 THEN 'Canceled'
ELSE 'Unknown'
END AS RUN_STATUS,
--CONVERT INTEGER DATE INTO SOMETHING MORE LEGABLE
SUBSTRING(CAST(A.RUN_DATE AS CHAR(8)),5,2) + '/' +
RIGHT(CAST(A.RUN_DATE AS CHAR(8)),2) + '/' +
LEFT(CAST(A.RUN_DATE AS CHAR(8)),4) AS RUN_DATE,
--CONVERT RUN_TIME INTO SOMETHING MORE RECONGNIZABLE (HH:MM:SS)
LEFT(RIGHT('000000' + CAST(A.RUN_TIME AS VARCHAR(10)),6),2) + ':' +
SUBSTRING(RIGHT('000000' + CAST(A.RUN_TIME AS VARCHAR(10)),6),3,2) + ':' +
RIGHT(RIGHT('000000' + CAST(A.RUN_TIME AS VARCHAR(10)),6),2) AS RUN_TIME,
--CONVERT RUN_DURATION INTO SOMETHING MORE RECONGNIZABLE (HH:MM:SS)
LEFT(RIGHT('000000' + CAST(A.RUN_DURATION AS VARCHAR(10)),6),2) + ':' +
SUBSTRING(RIGHT('000000' + CAST(A.RUN_DURATION AS VARCHAR(10)),6),3,2) + ':' +
RIGHT(RIGHT('000000' + CAST(A.RUN_DURATION AS VARCHAR(10)),6),2) AS RUN_DURATION,
--THE FOLLOWING SUBQUERY IS USED TO EXTRAPOLATE DETAILS FOR THE JOB IN IT'S MAINTENANCE PLAN (IF IT HAS 1)
--THE TOP 1 MAKES SURE WE GET ONLY 1 RECORD SINCE THIS IS A 1 TO MANY RELATIONSHIP
--THE LINE3 COLUMN CONTAINS DETAILS ABOUT THE TASK THAT WAS RUN
(SELECT TOP 1 E.LINE3
--WE START WITH THE SYSMAINTPLAN_LOG BECAUSE WE CAN (IN A WAY) JOIN IT TO OUR OUTER JOIN THROUGH THE PLAN_ID IN THE WHERE CLAUSE
FROM MSDB.DBO.SYSMAINTPLAN_LOG AS D
--NOW IT IS POSSIBLE TO, BY EXTENTION, JOIN SYSMAINTPLAN_LOGDETAIL TO THE OUTER JOIN AS WELL THROUGH ITS 1 TO 1 RELATIONSHIP WITH SYSMAINTPLAN_LOG
INNER JOIN MSDB.DBO.SYSMAINTPLAN_LOGDETAIL AS E ON E.TASK_DETAIL_ID = D.TASK_DETAIL_ID
--THE 1ST PART OF THE WHERE RETURNS ONLY RECORDS OF THE SAME PLAN_ID, ESSENTIALLY "JOINING" THIS RECORD TO THE OUTER JOIN THE IN MAIN QUERY
--THE 2ND PART MAKES SURE THE FIELD WE ACTUALLY CARE ABOUT CONTAINS MEANINGFUL DATA
WHERE D.PLAN_ID = C.PLAN_ID AND E.LINE3 != '') AS PLAN_DETAILS,
--THE FOLLOWING SUBQUERY RETURNS THE NAME OF THE MAINTENANCE PLAN (IF IT HAS 1)
(SELECT F.NAME
FROM MSDB.DBO.SYSMAINTPLAN_PLANS AS F --THIS IS A SYSTEM GENERATED VIEW
--LIKE THE ABOVE SUBQUERY, THIS WHERE ESSENTIALLY "JOINS" THIS RECORD TO THE OUTER JOIN IN THE MAIN QUERY
WHERE F.ID = C.PLAN_ID) AS PLAN_NAME
FROM MSDB.DBO.SYSJOBHISTORY AS A
INNER JOIN MSDB.DBO.SYSJOBS AS B ON A.JOB_ID = B.JOB_ID
--THIS OUTTER JOIN ATTACHES PLAN_IDS OF MAINTENANCE PLANS TO JOBS THAT HAVE THEM
LEFT OUTER JOIN SYSMAINTPLAN_SUBPLANS AS C ON C.JOB_ID = B.JOB_ID
--ONLY RETURN ENABLED JOBS
WHERE B.[ENABLED] = 1
--AND ONLY JOB OUTCOMES, NOT EACH STEP
AND A.STEP_ID = 0
--AND ONLY COMPLETED JOBS
AND A.RUN_STATUS <> 4
--SORTED BY LATEST DATE 1ST
ORDER BY A.RUN_DATE DESC
죄송하지만,이 포럼은 내 서식을 유지하지 않습니다. 어쨌든 그 후에, 패키지 변수 Instance ID를이 외래 키와 함께 이러한 레코드를 삽입하는 데 도움이되는 열로 추가합니다. 일부 문자열을 유니 코드로 변환합니다.이 코드는 여기 또는 여기에 없으며 그런 다음 유지 관리 계획 및 레코드없이 레코드에 대한 조건부 분할을 수행합니다. 내가 할 수있는 레코드가 없으면 대상에 삽입하기 만하면됩니다! 그러나 유지 관리 계획이있는 레코드의 경우 하나 이상의 DB에 연결할 가능성이 매우 높습니다. 그래서, 첫째로 작업 테이블에 작업 레코드를 삽입합니다 (정확하게 유지 관리 계획에없는 레코드로 수행). 그러면 방금 삽입 한 레코드를 찾기 위해 조회를 수행합니다. 다음으로 필자는 질의에서이 작업이 유지 관리 계획의 영향을받는 DB의 쉼표로 구분 된 목록을 가지고 VB.Net ArrayList로 구분합니다. 그런 다음 해당 ArrayList를 패키지 변수에 할당합니다.
이것은 내가있는 부분입니다. 분명히 내 다음 단계는 작업 ID를 사용하여 일종의 루프를 작성하여 ArrayList의 각 변수를 조회하여 DB/작업 피벗 테이블에 한 번에 하나씩 삽입하는 것입니다. 문제는 데이터 흐름 태스크 내에서 루프를 수행하는 방법을 알지 못하기 때문에이 작업에서 피벗 테이블 삽입을 이동하는 좋은 방법을 생각할 수 없습니다. 스크립트 구성 요소를 사용하여이 작업을 수행 할 수도 있지만 스크립트 작업 내에서 삽입을 미리 작성하는 방법을 잘 모르겠습니다 (고려해야 할 사항이 있습니까?). 저는 VB.Net과 C#뿐 아니라 TSQL에도 능통합니다. 그래서이 구현 방법을 조사 할 수 있습니다. 귀하의 도움에 미리 감사드립니다. 건배!
추신. 다음은 데이터를 삽입 할 테이블 구조입니다.
CREATE TABLE TBL_SERVERS(
ID INT UNIQUE IDENTITY(1,1),
TITLE NVARCHAR(50) PRIMARY KEY,
CLUSTER_NAME NVARCHAR(50) DEFAULT '',
RESOURCES_USED NVARCHAR(20) DEFAULT '',
RESOURCE_THRESHOLD NVARCHAR(20) DEFAULT '',
IS_CLUSTERED BIT NOT NULL DEFAULT 0)
CREATE TABLE TBL_INSTANCES(
ID INT UNIQUE IDENTITY(1,1),
SERVER_ID INT NOT NULL REFERENCES TBL_SERVERS(ID),
TITLE NVARCHAR(50) NOT NULL,
PRIMARY KEY (SERVER_ID,TITLE))
CREATE TABLE TBL_CATEGORY_TYPES(
ID INT UNIQUE IDENTITY(1,1),
TITLE NVARCHAR(50) PRIMARY KEY)
INSERT INTO TBL_CATEGORY_TYPES VALUES ('LOCAL')
INSERT INTO TBL_CATEGORY_TYPES VALUES ('MULTISERVER')
INSERT INTO TBL_CATEGORY_TYPES VALUES ('NONE')
CREATE TABLE TBL_CATEGORY_CLASSES(
ID INT UNIQUE IDENTITY(1,1),
TITLE NVARCHAR(50) PRIMARY KEY)
INSERT INTO TBL_CATEGORY_CLASSES VALUES ('JOB')
INSERT INTO TBL_CATEGORY_CLASSES VALUES ('ALERT')
INSERT INTO TBL_CATEGORY_CLASSES VALUES ('OPERATOR')
CREATE TABLE TBL_CATEGORIES(
ID INT UNIQUE IDENTITY(1,1),
TITLE NVARCHAR(50) NOT NULL,
CATEGORY_CLASS_ID INT NOT NULL REFERENCES TBL_CATEGORY_CLASSES(ID),
CATEGORY_TYPE_ID INT NOT NULL REFERENCES TBL_CATEGORY_TYPES(ID),
PRIMARY KEY (TITLE,CATEGORY_CLASS_ID))
CREATE TABLE TBL_SQL_JOBS(
ID INT PRIMARY KEY IDENTITY(1,1),
TITLE NVARCHAR(200) NOT NULL,
INSTANCE_ID INT NOT NULL REFERENCES TBL_INSTANCES(ID),
CATEGORY_ID INT NOT NULL REFERENCES TBL_CATEGORIES(ID),
RUN_STATUS NVARCHAR(10) NOT NULL,
RUN_DATE NVARCHAR(10) NOT NULL,
RUN_TIME NVARCHAR(8) NOT NULL,
RUN_DURATION NVARCHAR(8) NOT NULL,
MAINTENANCE_PLAN_NAME NVARCHAR(200),
RUN_INTERVAL NVARCHAR(20) DEFAULT '',
IS_ENABLED BIT NOT NULL DEFAULT 1)
SET IDENTITY_INSERT TBL_CATEGORIES ON
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (0,'[Uncategorized (Local)]',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (2,'[Uncategorized (Multi-Server)]',1,2,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (98,'[Uncategorized]',2,3,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (99,'[Uncategorized]',3,3,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (8,'Data Collector',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (7,'Database Engine Tuning Advisor',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (3,'Database Maintenance',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (5,'Full-Text',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (1,'Jobs from MSX',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (6,'Log Shipping',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (18,'REPL-Alert Response',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (16,'REPL-Checkup',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (10,'REPL-Distribution',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (11,'REPL-Distribution Cleanup',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (12,'REPL-History Cleanup',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (20,'Replication',2,3,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (13,'REPL-LogReader',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (14,'REPL-Merge',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (19,'REPL-QueueReader',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (15,'REPL-Snapshot',1,1,1)
INSERT INTO TBL_CATEGORIES (ID,TITLE,CATEGORY_CLASS_ID,CATEGORY_TYPE_ID,CATEGORY_GROUP_ID) VALUES (17,'REPL-Subscription Cleanup',1,1,1)
SET IDENTITY_INSERT TBL_CATEGORIES OFF
CREATE TABLE TBL_APPLICATIONS(
ID INT UNIQUE IDENTITY(1,1),
TITLE NVARCHAR(200) NOT NULL,
HUB_SITE NVARCHAR(50) DEFAULT '',
PRIMARY KEY (TITLE,HUB_SITE))
CREATE TABLE TBL_DATABASES(
ID INT UNIQUE IDENTITY(1,1),
INSTANCE_ID INT NOT NULL REFERENCES TBL_INSTANCES(ID),
TITLE NVARCHAR(200) NOT NULL,
APPLICATION_ID INT REFERENCES TBL_APPLICATIONS(ID),
MANAGED BIT NOT NULL DEFAULT 0,
CONNECTIONSTRING NVARCHAR(MAX) NOT NULL DEFAULT '',
RESOURCES_USED NVARCHAR(MAX) NOT NULL DEFAULT '',
RESOURCE_THRESHOLD NVARCHAR(MAX) NOT NULL DEFAULT '',
LAST_SEEN DATETIME NOT NULL DEFAULT GETDATE(),
PRIMARY KEY (INSTANCE_ID,TITLE))
CREATE TABLE TBL_DATABASE_JOBS(
ID INT UNIQUE IDENTITY(1,1),
DATABASE_ID INT NOT NULL REFERENCES TBL_DATABASES(ID),
JOB_ID INT NOT NULL REFERENCES TBL_SQL_JOBS(ID),
PRIMARY KEY (DATABASE_ID,JOB_ID))
그리고 이전에 게시 한 쿼리의 일부 샘플 결과는 다음과 같습니다.스크립트만큼이 모든 시스템 생성 된 테이블과 뷰를 사용하기 때문에 당신이 MSDB를 사용 인스턴스에 대해 실행할 수 있습니다 유의 사항 :
http://img253.imageshack.us/i/resultsn.jpg/
그냥이 패키지에 대한 내 목표에 대해 명확하게 않습니다. JOB_NAME, CATEGORY_ID, RUN_DATE, RUN_TIME, RUN_DURATION 및 PLAN_NAME은 모두 TBL_SQL_JOBS 테이블로 이동합니다. PLAN_DETAILS 열은 PLAN_NAME처럼 null을 수행하지 않지만 채워진 레코드의 경우 "Databases :"문자열을 제거하고 쉼표로 구분 된 데이터베이스 이름을 분리합니다. 그런 다음 분할 영역에서 TBL_Databases 테이블 (이전에 채워진 테이블)에 대한 DB 이름을 확인하고 해당 ID를 가져와야합니다. 그런 다음 처리중인 현재 작업 레코드의 ID와 결합하여 (패키지의 마지막 작업의 "조회 작업 ID"부분으로 생각할 수 있습니다)이 레코드를 TBL_DATABASE_JOBS 테이블에 별도로 추가합니다. 최종 결과는 고유 한 DB 목록과 Historical Job 정보 목록이있는 표와 그 사이의 표가 하나의 작업 : 다수의 DB 관계를 제공합니다. 다시 한번 감사드립니다.
우리는 절대로 친절하지 않지만 우리는 예의를 갖습니다. 해당 편집 영역 위에 101010 버튼이있어 문제의 코드를 형식화하는 데 도움이됩니다. – bobs