{"id":81255,"date":"2017-01-04T00:01:32","date_gmt":"2017-01-04T08:01:32","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/?p=81255"},"modified":"2019-02-18T09:10:15","modified_gmt":"2019-02-18T16:10:15","slug":"where-object-clauses-for-people-who-use-sql","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/where-object-clauses-for-people-who-use-sql\/","title":{"rendered":"Where[-Object] clauses for people who use SQL Server"},"content":{"rendered":"<p><strong>Summary:<\/strong>\u00a0Learn about the power of the\u00a0<span>Where[-Object] cmdlet in PowerShell.<\/span>\n<img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" alt=\"Hey, Scripting Guy! Question\" \/> Can I do a WHERE clause with an IN, in PowerShell?<\/p>\n<p style=\"padding-left: 30px\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" alt=\"Hey, Scripting Guy! Answer\" \/>\u00a0Yes!<\/p>\n<p>Today\u2019s post is from Aaron Nelson ( <a target=\"_blank\" href=\"http:\/\/sqlvariant.com\">blog<\/a> | <a target=\"_blank\" href=\"http:\/\/twitter.com\/SQLvariant\">twitter<\/a> ), who is a Microsoft MVP for SQL Server (Data Platform), leads the <a href=\"http:\/\/sqlps.io\">PowerShell<\/a> Virtual Chapters of PASS, volunteers for the local PASS Chapter <a href=\"http:\/\/www.atlantamdf.com\/\">AtlantaMDF<\/a>, and helps organize <a target=\"_blank\" href=\"http:\/\/sqlsaturday.com\">SQL Saturday<\/a> events in Atlanta.<\/p>\n<p>The PowerShell Virtual Chapter of PASS hosts monthly sessions on SQL Server + PowerShell, and you can find the recordings of those sessions on their <a target=\"_blank\" href=\"http:\/\/sqlps.io\/video\">YouTube channel<\/a>.<\/p>\n<p><code>Where[-Object]<\/code> is an extremely important cmdlet. Those of us who use SQL are accustomed to a rather rich experience when it comes to our <code>WHERE<\/code> clauses. Can we expect the same richness from <code>Where[-Object]<\/code>? While Where[-Object] does have <code>-and<\/code> and <code>-or<\/code>, we\u2019re used to more than just that. Today\u2019s post is an effort to get the word out about some options that were added starting back in PowerShell 3.0 because I found shockingly few examples of what I was trying to do.<\/p>\n<p>Before we begin, for comparison purposes, I will show how to do the same thing and receive the same results in both PowerShell and T-SQL. <u>To be clear<\/u>, if T-SQL is an option, you should usually use that unless the task wouldn\u2019t be easier to do in PowerShell.\u00a0 What is something that\u2019s easier to do in PowerShell than it is T-SQL, you ask? Backup databases, but that\u2019s a story for another day.<\/p>\n<p>I wanted to show an example of how to do the PowerShell equivalent of this query:<\/p>\n<p style=\"padding-left: 30px\"><code>SELECT name ,<\/code><\/p>\n<p style=\"padding-left: 90px\"><code>SCHEMA_NAME([schema_id]) AS 'SCHEMA_NAME'<\/code><\/p>\n<p style=\"padding-left: 60px\"><code>FROM SYS.tables<\/code><\/p>\n<p style=\"padding-left: 60px\"><code>WHERE SCHEMA_NAME([schema_id]) = 'Production'<\/code><\/p>\n<p style=\"padding-left: 60px\"><code>AND Name IN ('Product', 'TransactionHistory', 'TransactionHistoryArchive', 'WorkOrder', 'WorkOrderRouting')<\/code><\/p>\n<p>I knew that I could stack <code>WHERE<\/code> clauses and use <code>-or<\/code>, which leads me to the following statement. This code does work, but it\u2019s a chunky syntax, and I actually had a lot more than just five tables that I needed to query. The code would get verbose very quickly, so I wanted <em>smaller<\/em> syntax.<\/p>\n<p>A benefit of PowerShell over SQL syntax is that I can stack <code>WHERE<\/code> clauses, and if I need to, I could comment out one without having to rewrite the other. (Specifically, in the SQL language, I am not able to use the <code>WHERE<\/code> in succession like I can in PowerShell. It is a handy, but arguably lazy, coding trick that I am pointing out.)<\/p>\n<p style=\"padding-left: 30px\"><code>DIR SQLSERVER:\\SQL\\LocalHost\\DEFAULT\\Databases\\AdventureWorks2014\\tables |\nWHERE {$_.schema -eq 'Production'} |\nWHERE {$_.Name -eq \"Product\" -or\n$_.Name -eq \"TransactionHistory\" -or\n$_.Name -eq \"TransactionHistoryArchive\" -or\n$_.Name -eq \"WorkOrder\" -or\n$_.Name -eq \"WorkOrderRouting\"}<\/code><\/p>\n<p>I can shrink it a little by combining the <code>$_.Schema<\/code> portion, but I\u2019m looking for a lot more (or in this case, less).<\/p>\n<p style=\"padding-left: 30px\"><code>DIR SQLSERVER:\\SQL\\LocalHost\\DEFAULT\\Databases\\AdventureWorks2014\\tables |\nWHERE {$_.schema -eq 'Production' -and $_.Name -eq 'Product' -or\n$_.Name -eq 'TransactionHistory' -or\n$_.Name -eq 'TransactionHistoryArchive' -or\n$_.Name -eq 'WorkOrder' -or\n$_.Name -eq 'WorkOrderRouting'}<\/code><\/p>\n<p>I wanted a more efficient way, so I went searching. Eventually, I found <a target=\"_blank\" href=\"https:\/\/msdn.microsoft.com\/en-us\/powershell\/reference\/5.1\/microsoft.powershell.core\/where-object\">this MSDN page<\/a>, which did have a valid example, but it was literally the <u>only<\/u> reference for the -in operator on <code>Where[-Object]<\/code> that I have been able to find.<\/p>\n<p style=\"padding-left: 30px\"><code>Get-Process | where -Property ProcessName -in -Value \"Svchost\", \"TaskHost\", \"WsmProvHost\"<\/code><\/p>\n<p>Using that example, I was able to come up with this:<\/p>\n<p style=\"padding-left: 30px\"><code>&lt;# -In FTW! #&gt;\nDIR SQLSERVER:\\SQL\\LocalHost\\DEFAULT\\Databases\\AdventureWorks2014\\tables |\nWHERE {$_.schema -eq 'Production'} |\nWHERE -Property Name -In -Value \"Product\",\n\"TransactionHistory\",\n\"TransactionHistoryArchive\",\n\"WorkOrder\",\n\"WorkOrderRouting\";<\/code><\/p>\n<p>This is great and exactly what I need. Note, to match the syntax of the example and get it to work, I was forced to use two <code>WHERE<\/code> clauses again. This is because the example use the feature, which was introduced in in PowerShell 3.0, that allowed you to drop the <code>{}<\/code> for a single operator.<\/p>\n<p>The only question is: Is it efficient? What if that first <code>WHERE<\/code> on the schema name is only trimming it down to 10,000 tables? It could happen. So, the question is: Is there a way to do both <code>WHERE<\/code>s without having to use the pipeline?<\/p>\n<p>Well, you can use the <code>Where()<\/code> method, but it\u2019s less readable. I would only attempt the following syntax if I was sure that I needed to focus on pipeline efficiency. The syntax isn\u2019t really all <em>that<\/em> tough to read. In fact, it\u2019s kind of easier to read if you think of it as putting the <code>DIR<\/code> portion into a subquery. But, still, it might be overly confusing for a coworker who\u2019s trying to debug my code while I\u2019m out on vacation or something.<\/p>\n<p style=\"padding-left: 30px\"><strong>Note<\/strong>: The <code>.Where()<\/code> method is available in PowerShell 4.0\u00a0and later versions.\u00a0Also \u00a0note\u00a0that I dropped the <code>-Value<\/code> operator because it doesn\u2019t seem to be strictly necessary.<\/p>\n<p style=\"padding-left: 30px\"><code>(DIR SQLSERVER:\\SQL\\LocalHost\\DEFAULT\\Databases\\AdventureWorks2014\\tables ).WHERE({$_.schema -eq 'Production'}) |\nWHERE -Property Name -In \"Product\",\n\"TransactionHistory\",\n\"TransactionHistoryArchive\",\n\"WorkOrder\",\n\"WorkOrderRouting\";<\/code><\/p>\n<p>After digging some more, I learned that the answer I was looking for all along was surprisingly close to SQL syntax, but oddly, I couldn\u2019t find a single example that called it out for being this easy. Hence, the reason for this post.<\/p>\n<p style=\"padding-left: 30px\"><code>&lt;# Best way I have found so far. #&gt;\nDIR SQLSERVER:\\SQL\\LocalHost\\DEFAULT\\Databases\\AdventureWorks2014\\tables |\nWHERE {$_.schema -eq 'Production' -and $_.Name -In 'Product',\n'TransactionHistory',\n'TransactionHistoryArchive',\n'WorkOrder',\n'WorkOrderRouting'}<\/code><\/p>\n<p>This is stunningly similar to SQL syntax, at least to someone who has also been writing PowerShell code for the last seven years. It\u2019s so close, I will point out the differences in case you\u2019re a SQL person and need a guide to do this in PowerShell.<\/p>\n<ul>\n<li>You need to put <code>{}<\/code> around the entire portion of the <code>WHERE<\/code> clause that actually comes after the word, <code>WHERE<\/code>.<\/li>\n<li>We need to add <code>$_.<\/code> in front of our <em>column<\/em> names.<\/li>\n<li>Use <code>-eq<\/code> instead of <code>=<\/code>.<\/li>\n<li>Add a <code>\u2013<\/code> in front of <code>AND<\/code> and <code>IN<\/code> (and in front of <code>OR<\/code> if you were using that).\n<ul>\n<li>Side note: I\u2019m not demonstrating it today, but PowerShell does support wrapping portions of your <code>WHERE<\/code> clause that you want to logic together by using <code>()<\/code> which, as we all know, can be <u>extremely<\/u> important when you start sticking <code>OR<\/code>s in your <code>WHERE<\/code> clause.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Now, when I say, \u201c<em>Best way I have found so far<\/em>\u201d, I\u2019m talking about from a code readability standpoint.\u00a0 Again, if my <code>DIR<\/code> is going to produce 10,000+ tables, I should probably go with the <code>.Where()<\/code> method.\u00a0 However, if I\u2019m only dealing with a few hundred, piping to <code>WHERE<\/code> should turn out fine.<\/p>\n<p>Also, you might be asking: Can I provide an array as the values for the -In? Yes, yes you can!<\/p>\n<p style=\"padding-left: 30px\"><code>[array]$tblz = 'Product','TransactionHistory','TransactionHistoryArchive','WorkOrder','WorkOrderRouting';\nDIR SQLSERVER:\\SQL\\LocalHost\\DEFAULT\\Databases\\AdventureWorks2014\\tables |\nWHERE {$_.schema -eq 'Production'} |\nWHERE -Property Name -In $tblz;<\/code><\/p>\n<p>At this point, you\u2019re probably thinking \u201cShouldn\u2019t I just do this in T-SQL?\u201d If you\u2019re querying tables within a single database, yes, probably. If, on the other hand, you are trying to assemble information about tables in multiple databases and\/or across multiple SQL instance, that\u2019s a different story.<\/p>\n<p>On many occasions, I find myself using both PowerShell and T-SQL for what they\u2019re good at, at the same time. The following example does just that.<\/p>\n<p>In this script, we\u2019re going to poke around our environment for some potential space savings. In the PowerShell portion, we\u2019re going to iterate through our <a target=\"_blank\" href=\"https:\/\/technet.microsoft.com\/en-us\/library\/ms173574(v=sql.130).aspx\">Registered Servers<\/a> from SQL Server Management Studio and look at all the databases on those servers in which <code>IndexSpaceUsage<\/code> is more than 30% of the size of the <code>DataSpaceUsage<\/code> for the database. When PowerShell finds a database like that, it is going to fire off a T-SQL script to find indexes in that database that have been updated but not selected from since the last server reboot. When the T-SQL query finds one of those indexes, it passes that information back to PowerShell in the form of a .NET <code>DataTable<\/code>.<\/p>\n<p>What to do with those indexes from there is up to you, but now you know about them.<\/p>\n<p style=\"padding-left: 30px\"><code>&lt;#<\/code><\/p>\n<p style=\"padding-left: 60px\"><code>.DESCRIPTION\nGoes through all the SQL Server instances in your Registered Servers and looks for databases\nwhere more than 30% of the Data Space Used is taken up by indexes, then looks inside those\ndatabases for Indexes that have been updated but not scanned, seeked, or lookuped since\nthe last server reboot.<\/code><\/p>\n<p style=\"padding-left: 30px\"><code>#&gt;\n[array]$DemoDBs = 'AdventureWorks2012', 'AdventureWorks2014'<\/code><\/p>\n<p style=\"padding-left: 30px\"><code>$QueryIWantToRun = \"SELECT @@SERVERNAME AS 'ServerName',<\/code><\/p>\n<p style=\"padding-left: 120px\"><code>CASE @@SERVICENAME WHEN 'MSSQLSERVER' THEN 'Default' ELSE @@SERVICENAME END AS 'InstanceName',\ndatabase_id ,<\/code><\/p>\n<p style=\"padding-left: 90px\"><code>db_name(database_id) AS 'DatabaseName',\nSchema_Name(t.[schema_id]) AS 'SchemaName',<\/code><\/p>\n<p style=\"padding-left: 120px\"><code>t.name AS 'TableName',\ni.object_id ,<\/code><\/p>\n<p style=\"padding-left: 90px\"><code>i.name AS 'IndexName',\ni.index_id,\ni.type_desc ,\nOBJECT_NAME(iu.object_id) AS 'ObjectName',\nuser_seeks ,\nuser_scans ,\nuser_lookups ,\nuser_updates ,\nlast_user_seek ,<\/code><\/p>\n<p style=\"padding-left: 120px\"><code>last_user_scan ,<\/code><\/p>\n<p style=\"padding-left: 90px\"><code>last_user_lookup ,\nlast_user_update<\/code><\/p>\n<p style=\"padding-left: 60px\"><code>FROM SYS.TABLES T\nJOIN SYS.indexes i<\/code><\/p>\n<p style=\"padding-left: 90px\"><code>ON i.object_id = t.object_id<\/code><\/p>\n<p style=\"padding-left: 60px\"><code>LEFT OUTER JOIN sys.dm_db_index_usage_stats iu<\/code><\/p>\n<p style=\"padding-left: 90px\"><code>ON iu.object_id = i.object_id\nAND iu.index_id = i.index_id<\/code><\/p>\n<p style=\"padding-left: 60px\"><code>WHERE iu.database_id = DB_ID()<\/code><\/p>\n<p style=\"padding-left: 90px\"><code>AND i.type_desc = 'NONCLUSTERED'\nAND last_user_seek IS NULL\nAND last_user_scan IS NULL\nAND last_user_lookup IS NULL\nAND last_user_update IS NOT NULL\"<\/code><\/p>\n<p style=\"padding-left: 30px\"><code>foreach ($RegisteredSQLs IN dir -recurse SQLSERVER:\\SQLRegistration\\'Database Engine Server Group'\\ | WHERE {$_.Mode -ne 'd'} )\n{<\/code><\/p>\n<p style=\"padding-left: 60px\"><code>foreach($DB IN Get-SqlDatabase -ServerInstance $RegisteredSQLs.Name |\nWHERE {$_.IsSystemObject -EQ $false -and (($_.IndexSpaceUsage \/ $_.DataSpaceUsage) * 100) -GT 30 \u00a0-and $_.Name -notin $DemoDBs}\n)<\/code><\/p>\n<p style=\"padding-left: 60px\"><code>{<\/code><\/p>\n<p style=\"padding-left: 30px\"><code>$Results+=\u00a0\u00a0\u00a0 Invoke-Sqlcmd -ServerInstance $RegisteredSQLs.Name -Database $DB.Name -Query $QueryIWantToRun -OutputAs DataTables<\/code><\/p>\n<p style=\"padding-left: 60px\"><code>}<\/code><\/p>\n<p style=\"padding-left: 30px\"><code>}<\/code><\/p>\n<p style=\"padding-left: 30px\"><code>$Results | Format-Table -AutoSize;<\/code><\/p>\n<p>At the end of the day, PowerShell <code>WHERE<\/code> syntax behaves a lot like SQL syntax, at least for the basic operators that I tested (<code>Where<\/code>, <code>-and<\/code>, <code>-in<\/code>, and <code>-or<\/code>). It can even wrap portions of your <code>WHERE<\/code> clause in parentheses <code>()<\/code>, and that also behaves like SQL syntax. It is a wonderful capability to be able to use!<\/p>\n<p>Aaron Nelson\nMicrosoft MVP for SQL Server (Data Platform)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary:\u00a0Learn about the power of the\u00a0Where[-Object] cmdlet in PowerShell. Can I do a WHERE clause with an IN, in PowerShell? \u00a0Yes! Today\u2019s post is from Aaron Nelson ( blog | twitter ), who is a Microsoft MVP for SQL Server (Data Platform), leads the PowerShell Virtual Chapters of PASS, volunteers for the local PASS Chapter [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[568,641],"tags":[194,499,377,176],"class_list":["post-81255","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hey-scripting-guy","category-windows-powershell","tag-aaron-nelson","tag-guestblogger","tag-powershell","tag-sql-server"],"acf":[],"blog_post_summary":"<p>Summary:\u00a0Learn about the power of the\u00a0Where[-Object] cmdlet in PowerShell. Can I do a WHERE clause with an IN, in PowerShell? \u00a0Yes! Today\u2019s post is from Aaron Nelson ( blog | twitter ), who is a Microsoft MVP for SQL Server (Data Platform), leads the PowerShell Virtual Chapters of PASS, volunteers for the local PASS Chapter [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/81255","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=81255"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/81255\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=81255"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=81255"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=81255"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}