이 엔드투엔드 자습서에서는 프로젝트 상태를 추적하고, 업데이트를 데이터베이스에 다시 쓰고, Power BI 보고서의 알림을 Microsoft Teams에 게시하는 임시 작업 흐름을 만듭니다. 솔루션은 모든 상태 업데이트의 전체 기록을 유지 관리하므로 시간이 지남에 따라 프로젝트 상태가 어떻게 변경되었는지 추적할 수 있습니다. 이 자습서에서는 데이터 쓰기 저장을 외부 API 호출과 결합하여 완전한 통신 워크플로를 만드는 방법을 보여 줍니다.
이 튜토리얼에서는 다음을 배우게 됩니다:
- 전체 기록을 유지하는 프로젝트 및 상태 추적 테이블을 사용하여 Fabric에서 SQL 데이터베이스를 만듭니다.
- 구성을 별도로 저장하도록 변수 라이브러리를 설정합니다.
- 상태를 업데이트하고, 업데이트를 요청하고, Teams에 알림을 게시하는 사용자 데이터 함수를 구성합니다.
- 필요에 따라 Direct Lake 전망을 위해 구체화된 호수 전망을 사용하여 Lakehouse 바로 가기를 설정합니다.
- 데이터 함수 단추를 사용하여 사용자 데이터 함수를 Power BI 보고서와 통합합니다.
기존 패브릭 용량이 없는 경우 Fabric 평가판을 시작합니다.
사전 요구 사항
- Power BI Desktop. 디바이스에 Power BI Desktop이 설치되어 있지 않은 경우 Power BI Desktop 가져오기의 지침을 따르세요.
- 들어오는 웹후크를 추가할 수 있는 권한이 있는 Microsoft Teams 채널입니다.
개요
이 자습서에서는 사용자가 Power BI 보고서에서 직접 프로젝트 상태를 업데이트할 수 있는 프로젝트 추적 솔루션을 만듭니다. 사용자가 상태를 업데이트하면 시스템은 다음을 수행합니다.
- 모든 상태 업데이트의 전체 기록을 유지하면서 SQL 데이터베이스에 새 상태를 씁니다.
- 적응형 카드 알림을 Microsoft Teams에 보냅니다.
- 보고서를 새로 고쳐 업데이트된 데이터를 표시합니다.
메모
업데이트는 데이터 함수가 완료되고 보고서 페이지가 새로 고쳐진 후 일반적으로 함수 실행 시간, 쿼리 응답 시간 및 네트워크 조건과 같은 요인에 따라 몇 초 내에 보고서에 표시됩니다. 스토리지 가져오기 모드에서는 업데이트된 값이 표시되기 전에 의미 체계 모델을 별도로 새로 고쳐야 합니다.
사용자 흐름
워크플로는 보고서 사용자 간에 지속적인 피드백 루프를 만듭니다.
보고서에서 Teams를 통한 업데이트 요청 - 사용자가 보고서에서 프로젝트를 선택하고 상태 업데이트 요청을 보냅니다. 요청은 보고서에 대한 링크가 포함되어 Microsoft Teams에 게시됩니다.
Teams에서 알림 수신 및 보고서 열기 - 프로젝트 소유자는 Teams에서 알림을 보고 링크를 선택하여 보고서를 엽니다.
보고서의 업데이트 상태 — 프로젝트 소유자가 프로젝트를 선택하고, 새 상태를 선택하고, 메모를 추가하고, 업데이트 단추를 선택합니다.
업데이트 및 알림 보내기를 참조하세요 . 보고서에는 새 상태가 표시되고 변경 내용을 확인하는 알림이 Teams에 게시됩니다.
아키텍처
솔루션은 Microsoft Fabric 내에서 이러한 구성 요소를 연결합니다.
| 구성 요소 | Purpose |
|---|---|
| Fabric SQL Database | 전체 기록을 사용하여 프로젝트 및 상태 업데이트 레코드를 저장합니다.
Project 테이블, Status updates 테이블(모든 변경 내용의 전체 기록을 유지함) 및 Project status 뷰를 포함합니다. |
| 레이크하우스 (선택 사항) | Direct Lake 뷰에 대한 SQL 데이터베이스 테이블의 바로 가기를 제공합니다. 분석을 위해 구체화된 레이크 뷰가 필요한 경우에 사용합니다. |
| 변수 라이브러리 | Teams 웹후크 URL 및 보고서 URL과 같은 구성 값을 저장합니다. 함수를 다시 게시하지 않고 값을 업데이트합니다. |
| 사용자 데이터 함수 | SQL에 대한 쓰기 저장을 처리하고 적응형 카드를 통해 Microsoft Teams에 알림을 게시하는 Python 함수입니다. |
| Power BI 의미 체계 모델 | 데이터 모델, 관계 및 측정값을 정의합니다. Power BI Desktop에서 보고서를 사용하여 빌드되었지만 Power BI 서비스에 별도의 항목으로 존재합니다. |
| Power BI 보고서 | 사용자가 프로젝트를 보고, 새 상태를 선택하고, 데이터 함수 단추를 통해 업데이트를 트리거하는 사용자 인터페이스입니다. |
| 마이크로소프트 팀 | 상태 변경 내용이 포함된 적응형 카드 알림을 받고 보고서에 다시 연결합니다. |
데이터는 다음 두 방향으로 흐릅니다.
- 읽기 경로: Power BI는 SQL 데이터베이스(DirectQuery를 통해) 또는 Lakehouse(Direct Lake를 통해)에서 읽어 현재 프로젝트 상태를 표시합니다.
- 쓰기 경로: 사용자가 데이터 함수 단추를 선택하면 Power BI는 SQL 데이터베이스에 쓰고 Teams에 게시하는 사용자 데이터 함수를 호출합니다.
SQL 데이터베이스 만들기
이 시나리오에서는 프로젝트 추적 데이터를 사용합니다. Fabric에서 SQL 데이터베이스 만들기의 단계에 따라 패브릭 작업 영역에서 새 SQL 데이터베이스를 만듭니다.
데이터베이스 테이블 만들기
SQL 데이터베이스에서 새 쿼리 창을 엽니다.
다음 SQL 스크립트를 실행하여 Project 테이블을 만듭니다.
CREATE TABLE [Project] ( [Project id] INT NOT NULL, [Project name] NVARCHAR(200) NOT NULL, [Product name] NVARCHAR(200), [Description] NVARCHAR(4000), [Priority] NVARCHAR(20), [Start date] DATE, [Target end date] DATE, [Budget] DECIMAL(18,2), [Project manager] NVARCHAR(100), [Department] NVARCHAR(100), [Created date] DATETIME2, [Created by] NVARCHAR(100), [Is active] BIT, CONSTRAINT PK_Project PRIMARY KEY NONCLUSTERED ([Project id]) );상태 업데이트 테이블을 만들어 시간 경과에 따른 상태 변경 내용을 추적합니다.
CREATE TABLE [Status updates] ( [Update id] INT NOT NULL, [Project id] INT NOT NULL, [Status] NVARCHAR(50) NOT NULL, [Updated date] DATETIME2 NOT NULL, [Updated by] NVARCHAR(100) NOT NULL, [Notes] NVARCHAR(4000), CONSTRAINT PK_StatusUpdates PRIMARY KEY NONCLUSTERED ([Update id]) );각 프로젝트에 대한 최신 상태를 반환하는 뷰를 만듭니다.
CREATE VIEW [Project status] AS SELECT p.[Project id], p.[Project name], COALESCE(ls.[Latest status], 'Not Started') AS [Latest status], ls.[Latest notes] FROM [Project] p LEFT JOIN ( SELECT [Project id], [Status] AS [Latest status], [Notes] AS [Latest notes], ROW_NUMBER() OVER (PARTITION BY [Project id] ORDER BY [Update id] DESC) AS RowNum FROM [Status updates] ) ls ON p.[Project id] = ls.[Project id] AND ls.RowNum = 1;샘플 프로젝트 데이터 삽입:
INSERT INTO [Project] ([Project id], [Project name], [Product name], [Description], [Priority], [Start date], [Target end date], [Budget], [Project manager], [Department], [Created date], [Created by], [Is active]) VALUES (1, 'Best Practices with Power BI - FabCon Atlanta', 'FabCon Atlanta', 'Session covering Power BI best practices for enterprise deployments', 'High', '2026-01-15', '2026-03-20', 5000.00, 'person1@somecompany.com', 'Developer Relations', '2026-01-15', 'Admin', 1), (2, 'Translytical Task Flows - Build', 'Microsoft Build', 'Deep dive into translytical workloads and real-time analytics patterns', 'Critical', '2026-02-01', '2026-05-19', 7500.00, 'person2@somecompany.com', 'Product Engineering', '2026-02-01', 'Admin', 1), (3, 'Advanced DAX Patterns - FabCon Barcelona', 'FabCon Barcelona', 'Workshop on complex DAX calculations and optimization techniques', 'High', '2026-03-01', '2026-09-15', 6000.00, 'person1@somecompany.com', 'Developer Relations', '2026-02-20', 'Admin', 1), (4, 'Semantic Modeling Deep Dive - Ignite', 'Microsoft Ignite', 'Comprehensive session on semantic model design and best practices', 'High', '2026-01-10', '2026-11-18', 8000.00, 'person2@somecompany.com', 'Product Engineering', '2026-01-10', 'Admin', 1), (5, 'Custom Visuals in Power BI - FabCon Atlanta', 'FabCon Atlanta', 'Hands-on lab for building custom visuals with the Power BI SDK', 'Medium', '2025-12-01', '2026-03-20', 4500.00, 'person1@somecompany.com', 'Developer Relations', '2025-12-01', 'Admin', 1), (6, 'TMDL for Version Control - Build', 'Microsoft Build', 'Session on using TMDL for semantic model source control and CI/CD', 'Critical', '2025-11-15', '2026-02-15', 5500.00, 'person2@somecompany.com', 'Product Engineering', '2025-11-15', 'Admin', 1), (7, 'Real-time Analytics with Power BI - Ignite', 'Microsoft Ignite', 'Showcase of Direct Lake and real-time streaming capabilities', 'High', '2026-02-10', '2026-11-18', 7000.00, 'person1@somecompany.com', 'Developer Relations', '2026-02-10', 'Admin', 1), (8, 'Semantic Modeling Workshop - FabCon Barcelona', 'FabCon Barcelona', 'Interactive workshop on building enterprise-grade semantic models', 'High', '2026-04-01', '2026-09-15', 6500.00, 'person2@somecompany.com', 'Product Engineering', '2026-02-25', 'Admin', 1);샘플 상태 업데이트 삽입:
INSERT INTO [Status updates] ([Update id], [Project id], [Status], [Updated date], [Updated by], [Notes]) VALUES (1, 1, 'Not Started', '2026-01-15', 'person1@somecompany.com', 'Session abstract submitted and approved'), (2, 1, 'In Progress', '2026-01-25', 'person1@somecompany.com', 'Outline completed, starting slide deck'), (3, 1, 'In Progress', '2026-02-10', 'person1@somecompany.com', 'Demo environment setup in progress'), (4, 1, 'In Progress', '2026-02-25', 'person1@somecompany.com', 'First draft of presentation complete, scheduling dry run'), (5, 2, 'Not Started', '2026-02-01', 'person2@somecompany.com', 'Session proposal accepted for Build'), (6, 2, 'In Progress', '2026-02-08', 'person2@somecompany.com', 'Research phase - gathering customer scenarios'), (7, 2, 'In Progress', '2026-02-15', 'person2@somecompany.com', 'Architecture diagrams drafted'), (8, 2, 'In Progress', '2026-02-24', 'person2@somecompany.com', 'Building demo lakehouse environment'), (9, 3, 'Not Started', '2026-02-20', 'person1@somecompany.com', 'Call for speakers submission pending review'), (10, 4, 'Not Started', '2026-01-10', 'person2@somecompany.com', 'Initial brainstorming session with PM team'), (11, 4, 'In Progress', '2026-01-20', 'person2@somecompany.com', 'Content outline approved by leadership'), (12, 4, 'In Progress', '2026-02-05', 'person2@somecompany.com', 'Sample semantic models being developed'), (13, 5, 'Not Started', '2025-12-01', 'person1@somecompany.com', 'Lab environment requirements documented'), (14, 5, 'In Progress', '2025-12-15', 'person1@somecompany.com', 'SDK samples being prepared'), (15, 5, 'On Hold', '2026-01-10', 'person1@somecompany.com', 'Paused - waiting on SDK v5 release for new features'), (16, 6, 'Not Started', '2025-11-15', 'person2@somecompany.com', 'Session planning initiated'), (17, 6, 'In Progress', '2025-12-01', 'person2@somecompany.com', 'GitHub Actions workflow samples created'), (18, 6, 'In Progress', '2026-01-15', 'person2@somecompany.com', 'Dry run completed with internal team'), (19, 6, 'Completed', '2026-02-15', 'person2@somecompany.com', 'Session delivered at internal summit, ready for Build'), (20, 7, 'Not Started', '2026-02-10', 'person1@somecompany.com', 'Topic approved for Ignite breakout session'), (21, 7, 'In Progress', '2026-02-18', 'person1@somecompany.com', 'Eventstream demo scenarios identified'), (22, 7, 'In Progress', '2026-02-26', 'person1@somecompany.com', 'Direct Lake performance benchmarks in progress'), (23, 8, 'Not Started', '2026-02-25', 'person2@somecompany.com', 'Workshop format and duration confirmed');
변수 라이브러리 설정
변수 라이브러리는 구성 값을 함수 코드와 별도로 저장합니다. 이 분리는 주요 이점을 제공합니다. 사용자 데이터 함수를 편집하거나 다시 게시하지 않고도 웹후크 URL 또는 보고서 링크와 같은 값을 업데이트할 수 있습니다.
예를 들어 Teams 채널이 변경되거나 다른 보고서를 가리킬 필요가 있는 경우 변수 라이브러리 값을 업데이트하고 변경 내용이 즉시 적용됩니다. 코드 변경은 필요하지 않습니다.
패브릭 작업 영역에서 + 새 항목을 선택합니다.
데이터 개발 섹션까지 아래로 스크롤하고 변수 라이브러리를 선택합니다.
변수 라이브러리
ProjectVariables의 이름을 지정하고 만들기를 선택합니다.+ 새 변수를 선택하고 다음 변수를 추가합니다.
변수 이름 유형 설명 TEAMS_WEBHOOK_URL스트링 귀하의 Teams 수신 웹훅 URL POWERBI_REPORT_URL스트링 Power BI 보고서에 대한 URL(게시 후 추가됨) 각 변수를 추가한 후 저장 을 선택합니다.
Teams 웹후크 URL 가져오기
들어오는 웹후크 만들기의 단계에 따라 Teams 채널에 대한 웹후크를 만듭니다. 웹후크를 만든 후 URL을 복사하여 변수 라이브러리에 로 TEAMS_WEBHOOK_URL추가합니다.
중요합니다
이 URL을 가진 사람은 누구나 Teams 채널에 메시지를 게시할 수 있습니다.
사용자 데이터 함수 만들기
상태 업데이트 및 Teams 알림을 처리하는 사용자 데이터 함수 항목을 만듭니다.
패브릭 작업 영역에서 + 새 항목>사용자 데이터 함수를 선택합니다.
기본 코드를 다음 Python 코드로 바꿉다.
import fabric.functions as fn import logging from datetime import datetime udf = fn.UserDataFunctions() @udf.connection(argName="sqlDb", alias="ProjectTrackingDb") @udf.connection(argName="varLib", alias="ProjectVariables") @udf.function() def update_project_status( sqlDb: fn.FabricSqlConnection, varLib: fn.FabricVariablesClient, projectId: int, newStatus: str, updatedBy: str, notes: str, updatedDate: str ) -> str: """ Updates the status of a project by inserting a new record into the Status updates table and sends a Teams notification. """ logging.info(f"Updating status for Project ID: {projectId}") # Parse and validate the date try: parsed_date = datetime.fromisoformat(updatedDate) except ValueError: raise fn.UserThrownError( f"Invalid date format. Use ISO format: '2026-02-27T14:30:00'", {"providedDate": updatedDate} ) # Validate status value valid_statuses = ['Not Started', 'In Progress', 'On Hold', 'Completed', 'Cancelled'] if newStatus not in valid_statuses: raise fn.UserThrownError( f"Invalid status. Must be one of: {', '.join(valid_statuses)}", {"providedStatus": newStatus} ) connection = sqlDb.connect() cursor = connection.cursor() try: # Get the previous status cursor.execute(""" SELECT TOP 1 [Status] FROM [Status updates] WHERE [Project id] = ? ORDER BY [Update id] DESC """, (projectId,)) prev_row = cursor.fetchone() previous_status = prev_row[0] if prev_row else "Not Started" # Get the next Update ID cursor.execute("SELECT ISNULL(MAX([Update id]), 0) + 1 FROM [Status updates]") next_update_id = cursor.fetchone()[0] # Verify the project exists cursor.execute("SELECT [Project name] FROM [Project] WHERE [Project id] = ?", (projectId,)) project_row = cursor.fetchone() if not project_row: raise fn.UserThrownError(f"Project with ID {projectId} not found.") project_name = project_row[0] # Insert the new status update cursor.execute(""" INSERT INTO [Status updates] ([Update id], [Project id], [Status], [Updated date], [Updated by], [Notes]) VALUES (?, ?, ?, ?, ?, ?) """, (next_update_id, projectId, newStatus, parsed_date, updatedBy, notes)) connection.commit() # Send Teams notification _send_teams_update(varLib, project_name, previous_status, newStatus, updatedBy, notes) return f"Status updated for '{project_name}': {previous_status} → {newStatus}" except Exception as e: connection.rollback() raise finally: cursor.close() connection.close() def _send_teams_update(varLib, project_name, previous_status, new_status, updated_by, notes): """Helper function to send Teams notification.""" import requests import json variables = varLib.getVariables() webhook_url = variables.get("TEAMS_WEBHOOK_URL") report_url = variables.get("POWERBI_REPORT_URL") if not webhook_url: return adaptive_card = { "type": "message", "attachments": [{ "contentType": "application/vnd.microsoft.card.adaptive", "content": { "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "type": "AdaptiveCard", "version": "1.4", "body": [ { "type": "TextBlock", "size": "Large", "weight": "Bolder", "text": "📋 Project Status Update" }, { "type": "FactSet", "facts": [ {"title": "Project:", "value": project_name}, {"title": "Status:", "value": f"{previous_status} → {new_status}"}, {"title": "Updated By:", "value": updated_by} ] }, { "type": "TextBlock", "text": f"**Notes:** {notes}" if notes else "", "wrap": True } ], "actions": [ {"type": "Action.OpenUrl", "title": "View Project", "url": report_url} ] if report_url else [] } }] } requests.post(webhook_url, headers={"Content-Type": "application/json"}, data=json.dumps(adaptive_card), timeout=30) @udf.connection(argName="sqlDb", alias="ProjectTrackingDb") @udf.connection(argName="varLib", alias="ProjectVariables") @udf.function() def request_status_update( sqlDb: fn.FabricSqlConnection, varLib: fn.FabricVariablesClient, projectId: int, requestedBy: str, message: str ) -> str: """ Sends a Teams notification requesting a status update for a project. """ logging.info(f"Requesting status update for Project ID: {projectId}") connection = sqlDb.connect() cursor = connection.cursor() try: # Get project details cursor.execute(""" SELECT [Project name], [Project manager] FROM [Project] WHERE [Project id] = ? """, (projectId,)) project_row = cursor.fetchone() if not project_row: raise fn.UserThrownError(f"Project with ID {projectId} not found.") project_name = project_row[0] project_manager = project_row[1] # Get current status cursor.execute(""" SELECT TOP 1 [Status], [Updated date] FROM [Status updates] WHERE [Project id] = ? ORDER BY [Update id] DESC """, (projectId,)) status_row = cursor.fetchone() current_status = status_row[0] if status_row else "Not Started" last_updated = status_row[1].strftime("%Y-%m-%d") if status_row else "Never" # Send Teams notification _send_status_request(varLib, project_name, project_manager, current_status, last_updated, requestedBy, message) return f"Status update requested for '{project_name}' from {project_manager}" finally: cursor.close() connection.close() def _send_status_request(varLib, project_name, project_manager, current_status, last_updated, requested_by, message): """Helper function to send status update request via Teams.""" import requests import json variables = varLib.getVariables() webhook_url = variables.get("TEAMS_WEBHOOK_URL") report_url = variables.get("POWERBI_REPORT_URL") if not webhook_url: return adaptive_card = { "type": "message", "attachments": [{ "contentType": "application/vnd.microsoft.card.adaptive", "content": { "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "type": "AdaptiveCard", "version": "1.4", "body": [ { "type": "TextBlock", "size": "Large", "weight": "Bolder", "text": "📢 Status Update Requested" }, { "type": "FactSet", "facts": [ {"title": "Project:", "value": project_name}, {"title": "Owner:", "value": project_manager}, {"title": "Current Status:", "value": current_status}, {"title": "Last Updated:", "value": last_updated}, {"title": "Requested By:", "value": requested_by} ] }, { "type": "TextBlock", "text": f"**Message:** {message}" if message else "", "wrap": True } ], "actions": [ {"type": "Action.OpenUrl", "title": "Update Status", "url": report_url} ] if report_url else [] } }] } requests.post(webhook_url, headers={"Content-Type": "application/json"}, data=json.dumps(adaptive_card), timeout=30)연결을 구성합니다.
- 설정 또는 연결 패널을 선택합니다.
- Fabric SQL Database를 가리키는 연결을
ProjectTrackingDb추가합니다. - 변수 라이브러리를 가리키는 연결을
ProjectVariables추가합니다.
게시를 선택하여 함수를 배포합니다.
메모
Power BI 데이터 함수 단추와 함께 사용되는 함수는 문자열(-> str)을 반환해야 합니다. Power BI는 함수가 실행된 후 사용자에게 이 반환 값을 표시하여 작업 결과에 대한 피드백을 제공합니다.
update_project_status 함수 이해
이 함수는 update_project_status 새 상태 레코드를 SQL 데이터베이스에 쓰고 Teams 알림을 보냅니다. 사용자가 보고서에서 업데이트 단추를 선택하면 다음 흐름이 발생합니다.
Power BI는 함수를 호출 합니다. 데이터 함수 단추는 매개 변수(프로젝트 ID, 새 상태, 메모 등)를 사용자 데이터 함수에 전달합니다.
입력 유효성 검사 - 함수는 날짜 형식의 유효성을 검사하고 상태 값이 허용되는 옵션 중 하나인지 확인합니다.
쿼리 현재 상태 - 함수는 데이터베이스에서 이전 상태 및 프로젝트 이름을 검색합니다.
새 레코드 삽입 - 새 상태, 타임스탬프 및 메모가 있는 새 행이 테이블에 삽입
Status updates됩니다.Teams 알림 보내기 - 도우미 함수
_send_teams_update는 상태 변경을 보여 주는 적응형 카드를 Teams 채널에 게시합니다.결과 반환 - 이 함수는 Power BI가 사용자에게 표시하는 성공 메시지를 반환합니다.
request_status_update 함수 이해
이 함수는 request_status_update 프로젝트 소유자에게 상태 업데이트를 제공하도록 요청하는 Teams 알림을 보냅니다. 이 함수는 데이터베이스에 쓰지 않고 메시지만 보냅니다.
Power BI는 함수를 호출 합니다. 데이터 함수 단추는 프로젝트 ID, 요청자 이름 및 메시지를 함수에 전달합니다.
쿼리 프로젝트 세부 정보 - 함수는 데이터베이스에서 프로젝트 이름, 프로젝트 관리자 및 현재 상태를 검색합니다.
Teams 알림 보내기 - 도우미 함수
_send_status_request는 요청 세부 정보 및 보고서로 다시 연결되는 프로젝트 상태 업데이트 단추가 포함된 적응형 카드를 Teams 채널에 게시합니다.결과 반환 - 함수는 Power BI가 사용자에게 표시하는 확인 메시지를 반환합니다.
(선택 사항) Direct Lake 보기를 위한 Lakehouse 바로 가기 설정
Fabric SQL Database는 모든 데이터를 OneLake에 델타 테이블로 저장하므로 SQL 데이터베이스 테이블에 직접 Direct Lake 의미 체계 모델을 만들 수 있습니다. 그러나 Direct Lake는 SQL 데이터베이스에서 뷰를 읽을 수 없으며 테이블만 읽을 수 있습니다. Direct Lake에서 보기를 사용하려면 Lakehouse에서 SQL 데이터베이스 테이블에 대한 바로 가기를 만든 다음 해당 뷰를 정의합니다.
SQL 데이터베이스 테이블에 대한 바로 가기 만들기
패브릭 작업 영역에서 새 Lakehouse 를 만들고 스키마를 사용하도록 설정합니다.
Lakehouse 탐색기에서 스키마(예: dbo)를 마우스 오른쪽 단추로 클릭하고 새 테이블 바로 가기를 선택합니다.
OneLake 카탈로그에서 SQL 데이터베이스로 이동하여 테이블을 선택합니다
Project.반복하여
Status updates테이블에 대한 바로 가기를 만듭니다.
바로 가기는 데이터를 복제하지 않고 기본 델타 테이블에 대한 읽기 액세스를 제공합니다.
구체화된 레이크 뷰 만들기
레이크하우스에서 각 프로젝트의 최신 상태를 계산하는 구체화된 레이크 뷰를 만듭니다.
레이크하우스에서 머티리얼라이즈드 레이크 뷰 관리(미리 보기)를 선택합니다.
Spark SQL을 사용하여 새 Notebook을 엽니다.
다음 쿼리를 실행합니다.
CREATE MATERIALIZED LAKE VIEW IF NOT EXISTS dbo.project_status AS SELECT p.`Project id` AS ProjectId, p.`Project name` AS ProjectName, COALESCE(ls.LatestStatus, 'Not Started') AS LatestStatus, ls.LatestNotes FROM dbo.Project p LEFT JOIN ( SELECT `Project id` AS ProjectId, `Status` AS LatestStatus, `Notes` AS LatestNotes, ROW_NUMBER() OVER (PARTITION BY `Project id` ORDER BY `Update id` DESC) AS RowNum FROM dbo.`Status updates` ) ls ON p.`Project id` = ls.ProjectId AND ls.RowNum = 1;일정 켜기를 선택하고 빈도를 설정하여 보기 새로 고침을 예약합니다>.
메모
SQL 데이터베이스는 사용자 데이터 함수의 쓰기 대상으로 유지됩니다. Lakehouse 바로 가기는 구체화된 레이크 뷰를 통해 분석에 대한 읽기 전용 액세스를 제공합니다.
Power BI 보고서 만들기
DirectQuery 또는 Direct Lake를 사용하여 데이터에 연결할 수 있습니다.
- DirectQuery to SQL Database: 실시간 데이터는 사용자 정의 데이터 함수를 통해 데이터를 되돌려 쓸 수 있도록 지원합니다.
- Direct Lake에서 SQL Database 테이블로: Fabric SQL Database는 OneLake에 델타 테이블로 데이터를 저장하므로 Direct Lake는 테이블을 직접 읽을 수 있습니다.
- Lakehouse를 통한 Direct Lake(보기용) : Direct Lake는 SQL Database에서 보기를 읽을 수 없습니다. Direct Lake에서 뷰를 사용하려면 Lakehouse에 SQL 데이터베이스 테이블에 대한 바로 가기를 만들고, 그곳에서 물리적으로 정의된 레이크 뷰를 설정하십시오.
팁 (조언)
가져오기 모드를 사용할 수도 있습니다. 스토리지 모드에는 제한이 없습니다. 가져오기를 사용하면 업데이트된 값이 보고서에 표시되기 전에 의미 체계 모델을 새로 고쳐야 합니다.
옵션 A: DirectQuery를 통해 연결
Power BI Desktop를 열어보세요.
OneLake 카탈로그를 선택합니다.
패브릭 SQL 데이터베이스를 찾습니다.
SQL 분석 엔드포인트에 연결을 선택합니다.
Project,Status updates및Project status테이블/뷰를 선택합니다.스토리지 모드를 묻는 메시지가 표시되면 DirectQuery를 선택합니다.
옵션 B: Direct Lake를 통해 연결(분석 성능을 위해)
Power BI 서비스에서OneLake 카탈로그>를 선택합니다.
레이크하우스를 찾습니다.
바로 가기 테이블(
Project,Status updates) 및 구체화된 레이크 뷰(project_status)를 선택합니다.웹 모델링 환경에서 의미 체계 모델을 편집하여 측정값 및 관계를 추가합니다.
메모
Direct Lake를 사용하면 구체화된 레이크 뷰의 열 이름에 공백이 없습니다(예 ProjectId : 대신 Project id). 측정값과 일치하도록 의미 체계 모델의 열 이름을 바꿉니다.
상태 옵션 계산 테이블 만들기
단추 슬라이서의 상태 값을 제공하는 계산 테이블을 만듭니다. Power BI Desktop에서 다음 TMDL 스크립트를 실행합니다.
createOrReplace
table 'Status Options'
column Status
summarizeBy: none
isNameInferred
sourceColumn: [Status]
sortByColumn: 'Sort Order'
column Description
summarizeBy: none
isNameInferred
sourceColumn: [Description]
column 'Sort Order'
isHidden
formatString: 0
summarizeBy: sum
isNameInferred
sourceColumn: [Sort Order]
column 'Status Color'
summarizeBy: none
isNameInferred
sourceColumn: [Status Color]
partition 'Status Options' = calculated
mode: import
source =
DATATABLE(
"Status", STRING,
"Description", STRING,
"Sort Order", INTEGER,
"Status Color", STRING,
{
{ "Not Started", "Project has been created but work has not begun", 1, "#808080" },
{ "In Progress", "Active work is being performed on the project", 2, "#0078D4" },
{ "On Hold", "Project is paused pending resources, decisions, or dependencies", 3, "#FFB900" },
{ "Completed", "All project deliverables have been finished", 4, "#107C10" },
{ "Cancelled", "Project has been terminated and will not be completed", 5, "#D13438" }
}
)
지원 방안 만들기
데이터 함수 단추를 지원하는 측정값을 저장할 계산 테이블을 만듭니다. Power BI Desktop에서 다음 TMDL 스크립트를 실행합니다.
createOrReplace
table 'Translytical task flow'
/// Generates a preview of the Teams notification that will be sent when the user updates the status. Shows a warning if required selections are missing.
measure 'Preview of status update' = ```
VAR _ProjectId = SELECTEDVALUE(Project[Project id], 0)
VAR _ProjectName = SELECTEDVALUE(Project[Project name], "")
VAR _PreviousStatus = [Latest Status]
VAR _NewStatus = SELECTEDVALUE('Status Options'[Status], "N/A")
VAR _UpdatedBy = [Updated by]
VAR _UpdatedDate = FORMAT(NOW(), "YYYY-MM-DD HH:mm")
VAR _NL = UNICHAR(10)
RETURN
IF(_ProjectId = 0 || _NewStatus = "N/A",
"⚠️ Select a project and new status to preview",
"📋 Teams Notification Preview" & _NL &
"━━━━━━━━━━━━━━━━━━━━" & _NL &
"Project: " & _ProjectName & _NL &
"Status: " & _PreviousStatus & " → " & _NewStatus & _NL &
"Updated By: " & _UpdatedBy & _NL &
"Date: " & _UpdatedDate & _NL &
"Notes: See above" & _NL &
"━━━━━━━━━━━━━━━━━━━━" & _NL &
"📨 This will be sent to Teams"
)
```
/// Returns the email address of the current user. Used to track who made each status update.
measure 'Updated by' = USERPRINCIPALNAME()
/// Returns the most recent notes for the selected project. Only evaluates when a project is in scope.
measure 'Latest notes' =
IF(ISINSCOPE(Project[Project name]),
LASTNONBLANKVALUE('Status updates'[Update id], MAX('Status updates'[Notes])),
BLANK())
/// Returns the most recent status for the selected project by finding the last non-blank status value.
measure 'Latest status' =
IF(HASONEVALUE(Project[Project id]),
LASTNONBLANKVALUE('Status updates'[Update id], MAX('Status updates'[Status])),
BLANK())
/// Returns the Project ID when a single project is selected. Used as a parameter for the update_project_status and request_status_update functions.
measure 'Selected project id' = SELECTEDVALUE(Project[Project id])
formatString: 0
/// Returns today's date in ISO format. Used as the timestamp for status updates.
measure 'Updated date' = FORMAT(TODAY(), "yyyy-mm-dd")
/// Provides dynamic text for the update button showing the selected project and new status.
measure 'Update status button text' = "Update the status of " & SELECTEDVALUE(Project[Project name]) & " to " & SELECTEDVALUE('Status Options'[Status])
column Value
isHidden
formatString: 0
summarizeBy: sum
isNameInferred
sourceColumn: [Value]
partition 'Translytical task flow' = calculated
mode: import
source = {1}
메모
이 스크립트는 Translytical task flow 숨겨진 열이 있는 테이블을 만듭니다. 모든 열을 숨기면 측정값 테이블로 변환됩니다. 이 테이블은 특수 아이콘을 표시하고 항상 데이터 창의 맨 위에 표시되어 쉽게 액세스할 수 있습니다.
이러한 측정값은 다음과 같은 여러 용도로 사용됩니다.
| 측정 | Purpose |
|---|---|
Selected project id |
단일 프로젝트 행을 선택하면 프로젝트 ID를 캡처합니다. 사용자 데이터 함수에 매개 변수로 전달됩니다. |
Updated by |
를 통해 USERPRINCIPALNAME()현재 사용자의 전자 메일을 반환합니다. 각 상태 업데이트를 수행한 사용자를 추적합니다. |
Updated date |
함수 타임스탬프 매개 변수에 대한 오늘 날짜를 ISO 형식(yyyy-mm-dd)으로 반환합니다. |
Update status button text |
선택한 프로젝트와 새 상태를 보여 주는 동적 단추 레이블 지정을 제공합니다(예: "세션 ABC의 상태를 진행 중으로 업데이트"). |
Latest status |
상태 업데이트 테이블에서 마지막 항목을 찾는 데 사용하는 LASTNONBLANKVALUE 프로젝트의 최신 상태를 표시합니다. |
Latest notes |
프로젝트에 대한 최신 노트를 표시합니다. 특정 프로젝트가 범위에 있을 때만 평가됩니다. |
Preview of status update |
보내기 전에 Teams 알림의 미리 보기를 생성하여 사용자가 변경 내용을 확인하는 데 도움을 줍니다. 선택 항목이 누락된 경우 경고를 표시합니다. |
보고서 디자인
보고서 레이아웃은 프로젝트를 선택하고, 새 상태를 선택하고, 메모를 추가한 다음, 업데이트를 실행하는 명확한 워크플로를 안내합니다.
프로젝트 테이블 만들기
테이블 시각적 개체를 추가하여 프로젝트 정보를 표시합니다.
데이터에서 다음 열을 추가합니다.
Product nameProject nameTarget end dateDescription-
Latest status(상태 또는 프로젝트 상태 테이블/뷰에서) Latest notes
제목을 1로 설정 ) 업데이트할 프로젝트를 선택합니다.
대상 종료 날짜를 오름차순으로 정렬하여 예정된 마감일을 먼저 표시합니다.
상태 선택을 위한 단추 슬라이서 만들기
단추 슬라이서 시각적 요소를 추가합니다.
값 필드에 .를 추가
Status Options[Status]합니다.레이블 필드에서 각 상태 아래에 설명을 표시하도록 추가
FIRST(Status Options[Description])합니다.서식 창에서 다음을 수행합니다.
- 스타일을카드로 설정합니다.
- 방향을가로로 설정합니다.
- 최대 타일을 5로 설정합니다(각 상태에 대해 하나씩).
필드별로 각 카드에 색을 지정하도록 조건부 서식을 구성합니다
Status Color.제목을 2로 설정 ) 새 상태를 선택합니다.
노트에 대한 입력 슬라이서 추가
사용자가 상태 업데이트에 대한 메모를 입력할 수 있도록 입력 슬라이서 추가
제목을 3) 이 상태 업데이트에 대한 메모를 추가로 설정합니다.
요청 상태 업데이트 단추에서 사용하는 메시지 필드에 대한 다른 입력 슬라이서를 추가합니다.
제목을 팀 채널로 설정하거나 메시지를 보냅니다.
팁 (조언)
각 입력 슬라이서에 설명 제목을 지정합니다. 데이터 함수 단추를 구성하면 슬라이서가 제목으로 매개 변수 드롭다운에 표시되므로 올바른 함수를 보다 쉽게 식별할 수 있습니다. 구성 후 필요한 경우 보고서 캔버스에서 제목을 숨길 수 있습니다.
미리 보기 테이블 추가
단일 열인 측정값을 사용하여 테이블 시각적 개체를
[Preview of status update]추가합니다.제목을 미리 보기 업데이트로 설정합니다.
사용자가 Teams 알림을 보내기 전에 그 모양이 어떻게 보일지 보여줍니다.
데이터 함수 단추 추가
두 개의 단추를 추가합니다. 하나는 상태 업데이트용이고 다른 하나는 상태 업데이트를 요청하기 위한 것입니다.
상태 업데이트 단추
삽입 탭에서 단추>데이터 함수를 선택합니다.
서식 창에서 단추 텍스트를 구성합니다.
- 동적 레이블 지정을 위해
[Update status button text]측정값으로 설정합니다. - 비활성화된 텍스트를 "프로젝트 선택, 새 상태 및 먼저 노트 추가"와 같은 정적 텍스트로 설정합니다.
- 동적 레이블 지정을 위해
게시된 함수
update_project_status를 선택하세요.함수 매개 변수를 매핑합니다.
매개 변수 바인딩 유형 바인딩된 개체 projectId측정 [Selected project id]측정newStatus슬라이서 버튼 슬라이서 비주얼(자동 클리어 기능 활성화) updatedBy측정 [Updated by]측정notes슬라이서 입력 슬라이서 비주얼(자동 지우기 설정) updatedDate측정 [Updated date]측정작업 아래의 서식 창에서 성공적인 결과 후 보고서 새로 고침을 사용하도록 설정합니다. 이 설정은 함수가 성공적으로 실행된 후 보고서 페이지를 자동으로 새로 고칩니다.
팁 (조언)
슬라이서 매개 변수에 대해 자동 지우 기를 사용하도록 설정하면 사용자가 함수를 트리거한 후 단추 슬라이서와 노트 텍스트가 다시 설정됩니다.
메모
성공적인 결과 토글 후 보고서 새로 고침은 함수가 성공적으로 실행된 경우에만 보고서 페이지를 새로 고칩니다. DirectQuery 및 Direct Lake 스토리지 모드의 경우 새로 고친 시각적 개체는 의미 체계 모델을 통해 원본에 쿼리를 보내고, 일반적으로 몇 초 내에 최신 데이터를 반환하지만 정확한 타이밍은 데이터 함수 실행 시간, 쿼리 응답 시간 및 네트워크 조건과 같은 요인에 따라 달라집니다. 가져오기 모드의 경우 업데이트된 값이 보고서에 표시되기 전에 의미 체계 모델을 별도로 새로 고쳐야 합니다.
요청 상태 업데이트 단추
다른 Button>Data 함수를 추가합니다.
서식 창에서 단추 텍스트를 구성합니다.
- 기본 텍스트를 "채널에 Teams 메시지 보내기"와 같은 정적 텍스트로 설정합니다.
- 비활성화된 텍스트를 "프로젝트를 선택하고 메시지를 먼저 입력"으로 설정합니다.
게시된 함수
request_status_update를 선택하세요.함수 매개 변수를 매핑합니다.
매개 변수 바인딩 유형 바인딩된 개체 projectId측정 [Selected project id]측정requestedBy측정 [Updated by]측정message슬라이서 입력 슬라이서 비주얼(자동 지우기 설정) 필요에 따라 작업 아래의 서식 창에서 결과가 성공한 후 보고서 새로 고침을 사용하도록 설정합니다.
동적 단추 텍스트 구성
데이터 함수 단추의 동적 텍스트를 사용하여 사용자가 단추를 선택할 때 발생할 작업을 정확하게 표시합니다. 단추는 "업데이트"와 같은 일반 레이블 대신 "세션 ABC의 상태를 진행 중으로 업데이트"와 같은 컨텍스트별 텍스트를 표시할 수 있습니다.
동적 단추 텍스트를 구성하려면 다음을 수행합니다.
단추 레이블을 생성하는 측정값을 만듭니다. 예를 들어 이 측정값은 선택한 프로젝트 이름과 새 상태를 결합합니다.
Update status button text = "Update the status of " & SELECTEDVALUE(Project[Project name]) & " to " & SELECTEDVALUE('Status Options'[Status])데이터 함수 단추의 서식 창에서 단추>텍스트를 확장합니다.
기본 텍스트를 동적 측정값(
[Update status button text])으로 설정합니다.비활성화된 텍스트를 사용자에게 필요한 선택 항목을 알려주는 정적 텍스트로 설정합니다(예: "프로젝트 선택, 새 상태 및 먼저 노트 추가").
단추는 모든 필수 매개 변수에 값이 있을 때까지 비활성화된 텍스트를 표시합니다. 사용자가 선택한 후에는 특정 작업을 설명하는 동적 텍스트가 단추에 표시됩니다.
(선택 사항) 드릴스루 단추 및 페이지 추가
선택한 프로젝트의 상태 업데이트 전체 기록을 표시하려면 드릴스루 페이지를 추가할 수 있습니다.
삽입 탭에서 단추>빈을 선택합니다.
단추 아래의서식 창에서 텍스트를 설정합니다.
- 기본 텍스트: "모든 상태 업데이트 보기"
- 사용 안 함 텍스트: "모든 상태 업데이트를 보려면 프로젝트 선택"
작업에서 작업을 사용하도록 설정하고 다음 설정을 설정하십시오.
- 형식: 드릴스루
- 대상: 상태 기록 페이지 선택(다음 단계에서 생성됨)
새 페이지를 추가하고 이름을 상태 업데이트 기록으로 지정합니다.
페이지의 서식 창에서 페이지 정보를 확장하고 드릴스루를 사용하도록 설정합니다.
Project[Product name]를 드릴스루 필드로 추가합니다.상태 기록 표시를 위한 시각 자료를 추가합니다.
- 카드: 총 상태 업데이트 수
- 버튼 슬라이서: 상태별 분석
- 표: 모든 상태 업데이트(업데이트 ID, 업데이트 날짜, 상태, 메모, 업데이트 기준)
- 꺾은선형 차트: 시간에 따른 활동 갱신
사용자가 기본 보고서 페이지로 돌아갈 수 있도록 뒤로 단추를 추가합니다. 삽입 탭에서 뒤로 단추를> 선택합니다.
보고서 게시
보고서를 저장하고 Power BI 서비스에 게시합니다.
보고서 URL을 복사하여 변수 라이브러리에 로
POWERBI_REPORT_URL추가합니다.
워크플로 테스트
요청 상태 업데이트 흐름 테스트
게시되면 임시 작업 흐름을 사용하여 상태 업데이트를 요청할 수 있습니다.
업데이트할 프로젝트 선택 - 테이블에서 프로젝트 행을 선택하여 필터 컨텍스트를 설정합니다.
또는 팀 채널에 메시지를 보냅니다 . 입력 슬라이서에 메시지를 입력합니다(예: "이에 대한 업데이트를 받을 수 있나요?").
채널에 팀 메시지 보내기 단추를 선택합니다.
작업이 성공적으로 완료되면 요청 제출 확인 이 나타납니다.
요청 세부 정보가 포함된 프로젝트 상태 업데이트 적응형 카드에 대한 Teams 채널을 확인합니다.
프로젝트 소유자는 적응형 카드에서 프로젝트 상태 업데이트를 선택하여 보고서를 열고 상태를 업데이트할 수 있습니다.
업데이트 상태 흐름 테스트
게시되면 임시 작업 흐름을 사용하여 프로젝트 상태를 업데이트할 수 있습니다.
업데이트할 프로젝트 선택 - 테이블에서 프로젝트 행을 선택하여 필터 컨텍스트를 설정합니다.
새 상태는 무엇인가요? - 단추 슬라이서로 새 상태(예: 진행 중)를 선택합니다.
이 상태 업데이트에 대한 메모 추가 - 입력 슬라이서에 노트를 입력합니다(예: "데모 기록 시작").
업데이트 단추를 선택하여 상태 변경 내용을 레이크하우스에 다시 작성하고 Teams 알림을 보냅니다.
작업이 성공적으로 완료되면 요청 제출 확인 이 나타납니다.
상태 변경 세부 정보가 포함된 프로젝트 상태 업데이트 적응형 카드에 대한 Teams 채널을 확인합니다.
관련 콘텐츠
Translytical 작업 흐름
보고서 시각화
DAX 함수
패브릭 데이터
- 사용자 데이터 함수 개요
- 사용자 데이터 함수 만들기
- 데이터 원본에 사용자 데이터 함수 연결
- 변수 라이브러리 만들기 및 관리
- Fabric SQL Database 개요
- Lakehouse 개요
- Direct Lake 개요
- 구체화된 레이크 뷰 개요
마이크로소프트 팀