{"id":79674,"date":"2018-07-17T22:52:34","date_gmt":"2018-07-17T22:52:34","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=79674"},"modified":"2022-04-24T16:12:27","modified_gmt":"2022-04-24T16:12:27","slug":"power-bi-introduction-working-with-sql-server-data-in-power-bi-desktop-part-5","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/bi-sql-server\/power-bi-introduction-working-with-sql-server-data-in-power-bi-desktop-part-5\/","title":{"rendered":"Power BI Introduction: Working with SQL Server data in Power BI Desktop \u2014 Part 5"},"content":{"rendered":"<p><strong>The series so far:<\/strong><\/p>\n<ol>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/bi\/power-bi-part-1-introduction\/\">Power BI Introduction: Tour of Power BI \u2014 Part 1<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/bi\/power-bi-introduction-working-with-power-bi-desktop-part-2\/\">Power BI Introduction: Working with Power BI Desktop \u2014 Part 2<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/bi\/power-bi-introduction-working-with-r-scripts-in-power-bi-desktop-part-3\/\">Power BI Introduction: Working with R Scripts in Power BI Desktop \u2014 Part 3<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/bi\/power-bi-introduction-working-with-parameters-in-power-bi-desktop-part-4\/\">Power BI Introduction: Working with Parameters in Power BI Desktop \u2014 Part 4<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/bi\/power-bi-introduction-working-with-sql-server-data-in-power-bi-desktop-part-5\/\">Power BI Introduction:\u00a0Working with SQL Server data in Power BI Desktop \u2014 Part 5<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/homepage\/power-bi-introduction-power-query-m-formula-language-in-power-bi-desktop-part-6\/\">Power BI Introduction:\u00a0Power Query M Formula Language in Power BI Desktop \u2014 Part 6<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/bi\/power-bi-introduction-building-reports-in-power-bi-desktop-part-7\/\">Power BI Introduction: Building Reports in Power BI Desktop \u2014 Part 7<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/bi\/power-bi-introduction-publishing-reports-to-the-power-bi-service-part-8\/\">Power BI Introduction: Publishing Reports to the Power BI Service \u2014 Part 8<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/bi\/power-bi-introduction-visualizing-sql-server-audit-data-part-9\/\">Power BI Introduction: Visualizing SQL Server Audit Data \u2014 Part 9<\/a><\/li>\n<\/ol>\n\n<p>Power BI Desktop provides a far more robust environment for developing business intelligence reports than the Power BI service. Power BI Desktop supports more data sources and offers more tools for transforming the data retrieved from those sources.<\/p>\n<p>One data source available to Power BI Desktop that is not available to the service is SQL Server. Although the Power BI service provides connectors to Azure SQL Database and SQL Data Warehouse, it does not offer one for SQL Server. With Power BI Desktop, you can retrieve SQL Server data from entire tables or run queries that return a subset of data from multiple tables. You can also call stored procedures, including the <strong>sp_execute_external_script<\/strong> stored procedure, which allows you to run Python and R scripts.<\/p>\n<p>This article walks you through the process of retrieving data from a SQL Server instance, using different methods for returning the data. The article also covers some basic transformations. The examples are based on the <strong>AdventureWorks2017<\/strong> database, running on a local instance of SQL Server, but the principles apply to any SQL Server database.<\/p>\n<p>In fact, many of the topics covered here can apply to other relational database management systems and even other types of data sources. Because Power BI Desktop organizes all data into <em>queries<\/em> (table-like structures for working with datasets), once you get the data into Power BI Desktop, many of the actions you carry out are similar despite the source. That said, you\u2019ll still find features specific to relational databases, particularly when it comes to the relationships between tables.<\/p>\n<h2>Retrieving SQL Server Tables<\/h2>\n<p>In Power BI Desktop, you can retrieve SQL Server tables or views in their entirety. Power BI Desktop preserves their structures and, where possible, identifies the relationships between them. This section provides an example that demonstrates how importing tables works. If you follow along, you\u2019ll start by retrieving three tables from the <strong>AdventureWorks2017<\/strong> database.<\/p>\n<p>To retrieve the tables, click <em>Get Data<\/em> on the <em>Home<\/em> ribbon in the main Power BI Desktop window. When the <em>Get Data<\/em> dialog box appears, navigate to the <em>Database<\/em> category and double-click <em>SQL Server database<\/em>. In the <em>SQL Server database<\/em> dialog box, provide the name of the SQL Server instance and the target database, as shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"715\" height=\"337\" class=\"wp-image-79675\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-45.png\" \/><\/p>\n<p>For this article, I created two connection parameters. The first parameter, <em>SqlSrvInstance,<\/em> contains the name of the SQL Server instance. The second parameter, <em>SqlSrvDatabase,<\/em> contains the name of the database. When providing the connection information, you can use the actual names or you can create your own parameters. For details about creating parameters, refer to the <a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/bi\/power-bi-introduction-working-with-parameters-in-power-bi-desktop-part-4\/\">previous article<\/a> in this series.<\/p>\n<p>Once you\u2019ve entered the necessary information, click <em>OK<\/em>. When the <em>Navigator<\/em> dialog box appears, select the <em>Person.Address, Person.BusinessEntityAddress,<\/em> and <em>Person.Person<\/em> tables, as shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"949\" height=\"584\" class=\"wp-image-79676\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-46.png\" \/><\/p>\n<p>You can review the data from the selected table in the right pane. You can also choose to include related tables by clicking the <em>Select Related Tables<\/em> button. For example, if you select the <em>Person<\/em> table and then select the related tables, you would end up with nine tables, a lot more than you need for this example. Whether you take advantage of this option will depend on your specific project. If you do, but don\u2019t want to keep all the selected tables, simply clear the checkboxes associated with those you want to exclude.<\/p>\n<p>When you\u2019re ready to import the tables into Power BI Desktop, click the <em>Load<\/em> button. Any tables and views you\u2019ve selected will be loaded into Power BI Desktop and listed as individual datasets in <em>Data<\/em> view. From there, you can modify the datasets in Query Editor, just as you would data retrieved from any other source.<\/p>\n<p>One of the first steps you\u2019re likely to take in Query Editor is to rename each dataset and from there, remove any extra columns:<\/p>\n<ul>\n<li>\n<p>To rename a dataset, right-click the dataset in the <em>Queries<\/em> pane, click <em>Rename,<\/em> type in the new name, and press <em>Enter<\/em>.<\/p>\n<\/li>\n<li>\n<p>To remove a column, select the column in the main grid and click <em>Remove Columns<\/em> on the <em>Home<\/em> ribbon.<\/p>\n<\/li>\n<li>\n<p>To remove multiple columns in one operation, select the first column, press and hold <em>Control<\/em> as you select each additional column, and then click <em>Remove Columns<\/em> on the <em>Home<\/em> ribbon.<\/p>\n<\/li>\n<\/ul>\n<p>With these instruction in mind, take the following steps for the three tables you just imported:<\/p>\n<ul>\n<li>\n<p>Change the name of the <em>Person Address<\/em> table to <em>Address,<\/em> and then remove the columns <em>AddressLine1, AddressLine2, PostalCode, SpatialLocation, rowguid,<\/em> and <em>ModifiedDate<\/em>.<\/p>\n<\/li>\n<li>\n<p>Change the name of the <em>Person BusinessEntityAddress<\/em> table to <em>BusEntAddress,<\/em> and then remove the columns <em>AddressTypeID, rowguid,<\/em> and <em>ModifiedDate<\/em>.<\/p>\n<\/li>\n<li>\n<p>Change the name of the <em>Person Person<\/em> table to <em>Person,<\/em> and then remove the columns <em>PersonType, NameStyle, Title, MiddleName, Suffix, EmailPromotion, AdditionalContactInfo, Demographics, rowguid,<\/em> and <em>ModifiedDate<\/em>.<\/p>\n<\/li>\n<\/ul>\n<p>For now, ignore the columns that contain relationship data (the columns with the gold-colored values). We\u2019ll get back to those shortly.<\/p>\n<p>When you\u2019re finished updating the queries, apply your changes and close Query Editor. Your datasets should look like those shown in the following figure, as they appear in <em>Data<\/em> view. In this case, the <em>Person<\/em> dataset is selected.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"669\" height=\"441\" class=\"wp-image-79677\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-47.png\" \/><\/p>\n<p>Notice that each dataset now includes only two or three fields. You can also add filters in Query Editor to refine the data even more, or you can add filters to individual visualizations when you\u2019re building your reports.<\/p>\n<h2>Working with Relationships<\/h2>\n<p>When you updated your datasets in Query Editor, you no doubt noticed that the queries included a number of <em>pseudo-columns,<\/em> indicated by the long column names and gold-colored values, which are either <em>Table<\/em> or <em>Value<\/em>.<\/p>\n<p>The columns reflect the relationships that exist between the between tables in the source database. A column that contains <em>Table<\/em> values represents a foreign key in another table that references the primary table on which the query is based. A column that contains <em>Value<\/em> values represents a foreign key in the primary table that references another table.<\/p>\n<p>For example, when you select the <em>Address<\/em> query in Query Editor, you should see four relationship columns, as shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1164\" height=\"383\" class=\"wp-image-79678\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-48.png\" \/><\/p>\n<p>The columns indicate that the <strong>Address<\/strong> table, as it exists in the <strong>AdventureWorks2017<\/strong> database, contains one foreign key and is referenced by three foreign keys:<\/p>\n<ul>\n<li>\n<p>The <em>Person.BusinessEntityAddress<\/em> column in the <em>Address<\/em> query represents a foreign key in the <strong>Person.BusinessEntityAddress<\/strong> table that references the <strong>Person.Address<\/strong> table. The key is created on the <strong>AddressID<\/strong> column in the <strong>Person.BusinessEntityAddress<\/strong> table.<\/p>\n<\/li>\n<li>\n<p>The <em>Person.StateProvince<\/em> column in the <em>Address<\/em> query represents a foreign key in the <strong>Person.Address<\/strong> table that references the <strong>Person.StateProvince<\/strong> table. The key is created on the <strong>StateProvinceID<\/strong> column in the <strong>Person.Address<\/strong> table.<\/p>\n<\/li>\n<li>\n<p>The <em>Sales.SalesOrderHeader(AddressID)<\/em> column in the <em>Address<\/em> query represents a foreign key in the <strong>Sales.SalesOrderHeader<\/strong> table that references the <strong>Person.Address<\/strong> table. This key is created on the <strong>BillToAddress<\/strong> column in the <strong>Sales.SalesOrderHeader<\/strong> table.<\/p>\n<\/li>\n<li>\n<p>The <em>Sales.SalesOrderHeader(AddressID) 2<\/em> column in the <em>Address<\/em> query represents a foreign key in the <strong>Sales.SalesOrderHeader<\/strong> table that references the <strong>Person.Address<\/strong> table. This key is created on the <strong>ShipToAddress<\/strong> column in the <strong>Sales.SalesOrderHeader<\/strong> table.<\/p>\n<\/li>\n<\/ul>\n<p>If you click a <em>Value<\/em> or <em>Table<\/em> value, Query Editor will add a step to the <em>Applied Steps<\/em> section in the right pane and modify the dataset to include information specific to the selected value. For example, the first row in the <em>Address<\/em> query contains an <em>AddressID<\/em> value of 1 and a <em>StateProvinceID<\/em> value of 79. If you click the <em>Value<\/em> value in the <em>Person.StateProvince<\/em> column for that row, Query Editor will add a step named <em>1<\/em> to <em>Applied Steps<\/em> and modify the dataset to include only information from the <em>StateProvince<\/em> table specific to the <em>StateProvinceID<\/em> value of <em>79,<\/em> as shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1166\" height=\"323\" class=\"wp-image-79679\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-49.png\" \/><\/p>\n<p>You can click any instance of <em>Value<\/em> in the <em>Person.StateProvince<\/em> column to see the related data. The associated step in the <em>Applied Steps<\/em> section will be named after the <em>AddressID<\/em> value of the selected row. When you are finished viewing the results, you can return the query to its previous state by deleting the added steps in the <em>Applied Steps<\/em> section.<\/p>\n<p>If you were to now click the <em>Table<\/em> value in the <em>Person.BusinessEntityAddress<\/em> column for the first row, Query Editor would again add a step named <em>1<\/em>, only this time the information would come from the <em>BusinessEntityAddress<\/em> table, and the modified dataset would include only one row, as shown in the following figure. The row includes a foreign key reference to the <strong>AddressID<\/strong> value of <strong>1<\/strong> in the <strong>Address<\/strong> table.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1168\" height=\"295\" class=\"wp-image-79680\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-50.png\" \/><\/p>\n<p>You can play with the <em>Value<\/em> and <em>Table<\/em> values as much as you like to see the different related data. Just be sure to remove the step from <em>Applied Steps<\/em> to return the query to its previous state. Although you won\u2019t be using this feature for the examples in this article, you might find it useful for other projects based on SQL Server data.<\/p>\n<p>In addition to identifying foreign key relationships, Power BI Desktop also attempts to identify the relationships between the imported datasets. You can view these relationships by going to the <em>Relationships<\/em> pane in the main Power BI Desktop window. There you\u2019ll find a graphically representation of each dataset, which you can move around as necessary. If Power BI Desktop detects a relationship between two datasets, they\u2019re joined by a connector that indicates the type of relationship, as shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"880\" height=\"194\" class=\"wp-image-79681\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-51.png\" \/><\/p>\n<p>In this case, Power BI Desktop has detected a one-to-many relationship between the <em>Person<\/em> and <em>BusEntAddress<\/em> datasets and a one-to-one relationship between the <em>BusEntAddress<\/em> and <em>Address<\/em> datasets. You can view details about a relationship by double-clicking the connector. For example, to view details about the relationship between the <em>Person<\/em> and <em>BusEntAddress<\/em> datasets, double-click the connector that joins the datasets. This launches the <em>Edit relationship<\/em> dialog box, shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"722\" height=\"614\" class=\"wp-image-79682\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-52.png\" \/><\/p>\n<p>In the dialog box, you can view the details about the relationship and even modify them if necessary, although Power BI Desktop does a pretty good job at getting the relationships right, based on the current data in the dataset. Notice that the dialog box shows this as a many-to-one relationship, rather than one-to-many. This is because the <em>BusEntAddress<\/em> dataset is listed first<em>. <\/em>You can find details about defining and editing relationships, as well as the meaning of the individual options, in the Microsoft article <a href=\"https:\/\/docs.microsoft.com\/en-us\/power-bi\/desktop-create-and-manage-relationships#cross-filter-direction\">Create and manage relationships in Power BI Desktop<\/a>.<\/p>\n<p>The fact that Power BI Desktop detects relationships makes it easier to create visualizations based on multiple datasets. For example, I created a simple table visualization in <em>Report<\/em> view based on data from the <em>Person <\/em>and <em>Address<\/em> datasets, without having to map data across all three datasets. The following figure shows the table with a filter applied on the visualization (the <em>StateProvinceID<\/em> value set to <em>1<\/em>).<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"888\" height=\"575\" class=\"wp-image-79683\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-53.png\" \/><\/p>\n<p>We\u2019ll be digging into how to create visualizations in a later article in this series, so I won\u2019t be going into any details here. Just know that relationships can make this process simpler because the data is mapped for you.<\/p>\n<h2>Merging Datasets<\/h2>\n<p>In some cases, you might want to combine multiple datasets into a single one. For example, you might decide to merge the three datasets you created earlier. To do so, open Query Editor and select the <em>Person<\/em> query. On the <em>Home<\/em> ribbon, click the <em>Merge Queries<\/em> down arrow and then click <em>Merge Queries as New<\/em>.<\/p>\n<p>In the <em>Merge<\/em> dialog box (shown in the following figure), verify that the <em>Person<\/em> dataset is selected in the first drop-down list. Next, select <em>BusEntAddress<\/em> from the second (middle) drop-down list, and then select <em>Inner (only matching rows)<\/em> from the <em>Join Kind<\/em> drop-down list. This tells Query Editor to create an inner join between the two queries. Then, for each referenced dataset, select the <em>BusinessEntityID<\/em> column and click <em>OK<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"714\" height=\"610\" class=\"wp-image-79684\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-54.png\" \/><\/p>\n<p>When you click <em>OK,<\/em> Query Editor creates a new query, which you can rename <em>CityData<\/em>. The <em>CityData<\/em> query contains the three primary columns from the <em>Person<\/em> dataset, along with a number of relationship columns. Delete all the relationship columns except the last one, <em>BusEntAddress,<\/em> which represents the <em>BusEntAddress<\/em> query. Your merged query should now look like the one shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1122\" height=\"639\" class=\"wp-image-79685\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-55.png\" \/><\/p>\n<p>The next step is to select one or more columns from the <em>BusEntAddress<\/em> query to add to the merged query. To select the columns, click the icon at the top right corner of the <em>BusEntAddress<\/em> column and clear all but the <em>AddressID<\/em> column, as shown in the following figure. You do not need to add the <em>BusinessEntityID<\/em> column because it is already included in the <em>Person<\/em> dataset, and the other columns are relationship columns.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"476\" height=\"398\" class=\"wp-image-79686\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-56.png\" \/><\/p>\n<p>Also clear the <em>Use original column name as prefix<\/em> checkbox to keep the column name simple, and then click <em>OK<\/em>. The <em>CityData<\/em> query will now include the <em>AddressID<\/em> column.<\/p>\n<p>The next step is to merge the <em>Address<\/em> query into the <em>CityData<\/em> query. With the <em>CityData<\/em> query still selected in Query Editor, click the <em>Merge Queries<\/em> button on the <em>Home<\/em> ribbon. In the <em>Merge<\/em> dialog box (shown in the following figure), select <em>Address<\/em> from the second drop-down list and select <em>Inner (only matching rows)<\/em> from the <em>Join Kind<\/em> drop-down list. For each data set, select the <em>AddressID<\/em> column and then click <em>OK<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"717\" height=\"612\" class=\"wp-image-79687\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-57.png\" \/><\/p>\n<p>Next, click the icon at the top right corner of the <em>Address<\/em> reference column and clear all but the <em>City<\/em> and <em>StateProvinceID<\/em> columns. Also clear the <em>Use original column name as prefix<\/em> checkbox, if selected, and then click <em>OK<\/em>. Your merged dataset should now look like the one in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"927\" height=\"514\" class=\"wp-image-79688\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-58.png\" \/><\/p>\n<p>With the merged query in place, you have a single dataset from which you can perform other operations. For example, you can apply additional transformations such as pivoting data, splitting columns, or filtering rows, while still preserving the original datasets. A single dataset can also make it easier create visualizations because you don\u2019t have to navigate multiple sources. Like any feature in Power BI Desktop, your specific requirements will determine whether you can benefit from merged queries.<\/p>\n<h2>Using T-SQL Queries to Retrieve SQL Server Data<\/h2>\n<p>Although you can transform data in a variety of ways in Power BI Desktop, one of the most powerful tools you have at your disposal is the ability to use T-SQL queries to return data from a SQL Server database, rather than specifying individual tables or views. With a query, you can retrieve exactly the data you want, without having to remove columns, filter rows, or take other steps after importing the data. In this way, you\u2019re working with a single dataset that includes exactly the data you need, rather than trying to navigate multiple datasets that contain a lot of data you don\u2019t want.<\/p>\n<p>In the next example, you\u2019ll use the following <strong>SELECT<\/strong> statement to join together six tables in the <strong>AdventureWorks2017<\/strong> database and return the data to Power BI Desktop:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">SELECT cr.Name AS Country, st.Name AS Territory, \r\n p.LastName + ', ' + p.FirstName AS FullName\r\nFROM Person.Person p \r\n  INNER JOIN Person.BusinessEntityAddress bea \r\n    ON p.BusinessEntityID = bea.BusinessEntityID\r\n  INNER JOIN Person.Address a\r\n    ON bea.AddressID = a.AddressID\r\n  INNER JOIN Person.StateProvince sp\r\n    ON a.StateProvinceID = sp.StateProvinceID\r\n  INNER JOIN Person.CountryRegion cr\r\n    ON sp.CountryRegionCode = cr.CountryRegionCode\r\n  INNER JOIN Sales.SalesTerritory st\r\n    ON sp.TerritoryID = st.TerritoryID\r\nWHERE PersonType = 'IN' AND st.[Group] = 'North America' \r\nORDER BY cr.Name, st.Name, p.LastName, p.FirstName;<\/pre>\n<p>To run the query, click <em>Get Data<\/em> on the <em>Home<\/em> ribbon in the main Power BI Desktop window. When the <em>Get Data<\/em> dialog box appears, navigate to the <em>Database<\/em> category and double-click <em>SQL Server database<\/em>.<\/p>\n<p>In the <em>SQL Server database<\/em> dialog box, provide the name of the SQL Server instance and the target database and then click the <em>Advanced options<\/em> arrow, which expands the dialog box. In the <em>SQL statement<\/em> box, type or paste the above <strong>SELECT<\/strong> statement, as shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"716\" height=\"676\" class=\"wp-image-79689\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-59.png\" \/><\/p>\n<p>When you click <em>OK,<\/em> Power BI Desktop displays a preview window, showing you a subset of the data you\u2019ll be importing. Click <em>Load<\/em> to import the data into Power BI Desktop. After the data has loaded, go to <em>Data<\/em> view, right-click the new dataset, and then click <em>Rename<\/em>. Type <em>CountryData<\/em> and press <em>Enter<\/em>. The new dataset should look similar to the one shown in the following figure.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"698\" height=\"454\" class=\"wp-image-79690\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-60.png\" \/><\/p>\n<p>Now you have the dataset exactly as you need it, without all the extra steps that come with importing individual tables. You can still apply additional transformations if necessary, but often that will not be needed.<\/p>\n<p>In Power BI Desktop, you can run a wide range of T-SQL queries when retrieving data from a SQL Server database, including <strong>EXECUTE<\/strong> statements that call stored procedures. For example, you can call the <strong>sp_execute_external_script<\/strong> stored procedure in order to run an R script (SQL Server 2016 or later) or Python script (SQL Server 2017 or later), as shown in the following example:<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">DECLARE @pscript NVARCHAR(MAX);\r\nSET @pscript = N'\r\n# import Python modules\r\nimport pandas as pd\r\nfrom sklearn.datasets import load_iris\r\nfrom sklearn.model_selection import train_test_split\r\nfrom microsoftml import rx_oneclass_svm, rx_predict\r\n# create data frame\r\niris = load_iris()\r\ndf = pd.DataFrame(iris.data)\r\ndf.reset_index(inplace=True)\r\ndf.columns = [\"Plant\", \"SepalLength\", \"SepalWidth\", \"PetalLength\", \"PetalWidth\"]\r\n# split data frame into training and test data\r\ntrain, test = train_test_split(df, test_size=.06)\r\n# generate model\r\nsvm = rx_oneclass_svm(\r\n  formula=\"~ SepalLength + SepalWidth + PetalLength + PetalWidth\", data=train)\r\n# add anomalies to test data\r\ntest2 = pd.DataFrame(data=dict(\r\nPlant = [175, 200],\r\nSepalLength = [2.9, 3.1], \r\nSepalWidth = [.85, 1.1],\r\nPetalLength = [2.6, 2.5], \r\nPetalWidth = [2.7, 3.2]))\r\ntest = test.append(test2)\r\n# score test data\r\nscores = rx_predict(svm, data=test, extra_vars_to_write=\"Plant\")\r\nOutputDataSet = scores';\r\nEXEC sp_execute_external_script\r\n  @language = N'Python',\r\n  @script = @pscript\r\n  WITH RESULT SETS(\r\n    (SpeciesID INT, Score FLOAT(25))); <\/pre>\n<div class=\"note\">\n<p><em>NOTE: You need to have Machine Learning Services (In-Database) installed and enable the sp_execute_external_script property to run Python in SQL Server.<\/em><\/p>\n<\/div>\n<p>In this case, the <strong>sp_execute_external_script<\/strong> stored procedure is running a Python script that identifies anomalies in a sample dataset containing iris flower data. I based this example on one in a previous article I wrote, <a href=\"https:\/\/www.red-gate.com\/simple-talk\/sql\/bi\/sql-server-machine-learning-services-part-4-finding-data-anomalies-python\/\">SQL Server Machine Learning Services \u2013 Part 4: Finding Data Anomalies with Python<\/a>, which is part of a series on Python in SQL Server. Refer to that article for a full explanation of how this statement works.<\/p>\n<p>If you run this script, you should end up with the dataset similar to the one shown in the following figure, renamed to <em>IrisData<\/em>. (Because you\u2019re working with random data, the values will usually be different each time you run the query.) The dataset includes the IDs used to identify iris species and scores that help to determine anomalies in the data.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"615\" height=\"357\" class=\"wp-image-79691\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-61.png\" \/><\/p>\n<p>Although this example does not include SQL Server data, it demonstrates that you can run a Python script from Power BI Desktop. You can also create a script that includes SQL Server data or data from multiple sources, opening up an even wider range of possibilities for pulling data into Power BI Desktop.<\/p>\n<p>Best of all, you can take advantage of Python\u2019s analytical capabilities, while importing the data in exactly the format you need, allowing you to easily create visualizations that provide critical insights into the available information. For example, I created a <em>Scatter chart<\/em> visualization based on this <em>IrisData<\/em> dataset, as shown in the following figure. Notice the two points in the chart toward the upper right corner. These represent the anomalies identified by the Python script.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1089\" height=\"528\" class=\"wp-image-79692\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/07\/word-image-62.png\" \/><\/p>\n<h2>Making the Most of SQL Server Data<\/h2>\n<p>The ability to run T-SQL queries in Power BI Desktop gives you a powerful tool for accessing SQL Server data. Not only does this allow you to maximize the benefits of the SQL Server query engine, but also minimize the size of the datasets you import into Power BI Desktop, while reducing the number of transformations you have to perform.<\/p>\n<p>Of course, you must understand how to use T-SQL in order to take this approach, but if you do\u2014or can get someone who does\u2014you\u2019ll have a great deal of flexibility for working with SQL Server data. That said, even if you retrieve data on a table-by-table basis, you still have a number of effective tools for working with SQL Server data and preparing it for creating meaningful visualizations that can be posted to the Power BI service.<\/p>\n<p>Although the Power BI service lets you retrieve data from a number of sources, it does not provide a data connector for SQL Server. Of course, you can export SQL Server data to a file and then import that file into the service, but you cannot connect directly from the service to SQL Server, despite the critical role that SQL Server continues to play in many of today\u2019s organizations. The better you understand how to import and transform SQL Server data in Power BI Desktop, the more effectively you can visualize SQL Server data in a variety of ways.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Data for Power BI can come from many sources, but often the data is hosted in SQL Server. In this article, the fifth of the series, Robert Sheldon demonstrates how to work with SQL Server data in Power BI Desktop, including relationships between tables. &hellip;<\/p>\n","protected":false},"author":221841,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143528],"tags":[],"coauthors":[6779],"class_list":["post-79674","post","type-post","status-publish","format-standard","hentry","category-bi-sql-server"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/79674","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221841"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=79674"}],"version-history":[{"count":8,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/79674\/revisions"}],"predecessor-version":[{"id":79887,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/79674\/revisions\/79887"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=79674"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=79674"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=79674"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=79674"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}