SQL Server Get a column from results of EXEC that executes a dynamic query

wi3ka0sx  于 2023-06-04  发布在  其他
关注(0)|答案(2)|浏览(233)
select 
       [OrderTypeName]
      ,EXEC('SELECT TOP 1 [Status] 
              FROM dbo.Order_' + t_ros. 
            [OrderTypeName]) as [Status]

FROM dbo.OrderTypes t_ros

Sample Data:

OrderTypeName
-------------
ABC
XYZ
...

Views: dbo.Order_ABC, dbo.Order_XYZ....etc.

I have many kinds of orders that are stored in different tables. These tables have different structure and I am trying to get common structure using views that has the same name as the type of Order. I know the above code is not the correct way and is also showing me errors because I can't use EXEC inside select. But I am unable to find the correct way to achieve this. Please help.

qoefvg9y

qoefvg9y1#

Credit to @abolfazl-sadeghi as this is basically just a fixed up version of what he suggested - instead of trying to use EXEC inside the query, instead build a union query dynamically then EXEC once.

As already discussed, this is obviously not an ideal way to be doing things, but I appreciate you are constrained by the existing design.

To improve the resilience of this going forward, I have also added a join to the system schema to verify that the views actually exist and have a [Status] column. That way if someone drops a view, or adds a bad entry to the ordertypes table, it will still work. It wont currently handle the case where you have a variety of column types for [Status] - you could work around that by converting to varchar in the "TOP 1" query - but obviously then the output would be a varchar, and that might not be what you want. You could also constrain to a column type.

DECLARE @sql VARCHAR(MAX) = '';
SELECT @sql = STRING_AGG(' select ''' + [OrderTypeName] + ''',(SELECT TOP 1 [Status] from dbo.Order_' + [OrderTypeName] + ') as [Status]', ' union ')
FROM dbo.orderTypes ot
INNER JOIN INFORMATION_SCHEMA.COLUMNS c 
    ON c.TABLE_SCHEMA = 'dbo'
    AND c.TABLE_NAME = 'Order_' + [ot].[OrderTypeName]
    AND c.COLUMN_NAME = 'Status';
EXEC (@sql);
bfhwhh0e

bfhwhh0e2#

You need to put the whole thing into dynamic SQL, you cannot execute dynamic SQL in the middle of a query.

DECLARE @sql nvarchar(max);

SELECT @sql = STRING_AGG('
SELECT
  ' + QUOTENAME(OrderTypeName, '''') + ' AS OrderTypeName,
  (SELECT TOP (1) Status
   FROM dbo.' + QUOTENAME('Order_' + ot.OrderTypeName) + '
  ) AS Status
',' UNION ALL ')
FROM OrderTypes ot
JOIN sys.tables t ON t.name = 'Order_' + ot.OrderTypeName
JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE s.name = 'dbo';

PRINT @sql;   -- your friend

EXEC sp_executesql @sql;

Note the use of QUOTENAME to correctly escape names.

You can use sp_executesql to pass parameters to the dynamic query.

相关问题