Функция sql server возвращает строки из нескольких таблиц [duplicate]

Легко в MySQL:

  Пользователи UPDATE AS U1, пользователи AS U2 SET U1.name_one = U2.name_colX WHERE U2.user_id = U1.user_id  
19
задан Joe Enos 20 November 2013 в 00:16
поделиться

7 ответов

Кажется, что нет простого простого способа сделать это без взлома или серьезного сдвига парадигмы. Похоже, что лучший способ состоит в том, чтобы просто отделить исходные procs и завершить еще один процесс, чем раньше:

Старый способ:

create procedure dbo.GetSomething
as
begin
    select * from dbo.Person;
    select * from dbo.Car;
end;

Новый способ:

create procedure dbo.GetPeople
as
begin
    select * from dbo.Person;
end;

create procedure dbo.GetCars
as
begin
    select * from dbo.Car;
end;

-- This gives the same result as before
create procedure dbo.GetSomething
as
begin
    exec dbo.GetPeople;
    exec dbo.GetCars;
end;

Тогда, когда я нахожусь в другом proc и нуждаюсь в обоих наборах результатов, мне просто нужно будет называть их по одному.

2
ответ дан Joe Enos 16 August 2018 в 11:17
поделиться

Вы можете поместить несколько результирующих наборов в виде xml в таблицу

. Таким образом, когда вы хотите получить доступ ко всем этим результатам, вы проанализируете столбец с результатом в табличной форме

2
ответ дан abdulla wasay 16 August 2018 в 11:17
поделиться

На землях TSQL вы застряли.

Вот трюк (некоторые могут вызвать полу-хаки), который я использовал один раз.

/*  START TSQL CODE */

/*  Stored Procedure Definition */

Use Northwind
GO


IF EXISTS 
    (
    SELECT * FROM INFORMATION_SCHEMA.ROUTINES
    WHERE ROUTINE_TYPE = N'PROCEDURE' and ROUTINE_SCHEMA = N'dbo' and ROUTINE_NAME = N'uspOrderDetailsByCustomerId'  
    )
BEGIN
    DROP PROCEDURE [dbo].[uspOrderDetailsByCustomerId]
END


GO

CREATE Procedure dbo.uspOrderDetailsByCustomerId
(
  @CustomerID nchar(5)
, @ResultSetIndicator smallint = 0
)
AS

BEGIN

    SET NOCOUNT ON



    /* ResultSet #1 */

    if (@ResultSetIndicator = 0 OR @ResultSetIndicator = 1)
    BEGIN 
        SELECT 
            c.CustomerID, c.CompanyName /*,c.ContactName,c.ContactTitle,c.[Address],c.City,c.Region,c.PostalCode,c.Country ,c.Phone,c.Fax */
        FROM 
            Customers c 
            JOIN Orders o ON c.CustomerID = o.CustomerID 
        WHERE 
            c.CustomerID = @CustomerID
    END


    /* */
    /* ResultSet #2 */ 

    if (@ResultSetIndicator = 0 OR @ResultSetIndicator = 2)
    BEGIN 

        SELECT o.OrderID,o.CustomerID /* ,o.EmployeeID,o.OrderDate,o.RequiredDate,o.ShippedDate,o.ShipVia ,o.Freight,o.ShipName,o.ShipAddress,o.OrderID,o.CustomerID,o.EmployeeID,o.OrderDate  */
        FROM 
            Orders o 
         WHERE 
            o.CustomerID = @CustomerID
        ORDER BY 
            o.CustomerID , o.OrderID 

    END


    /* */
    /* ResultSet #3 */

    if (@ResultSetIndicator = 0 OR @ResultSetIndicator = 3)
    BEGIN 
         SELECT od.OrderID,od.ProductID /* ,od.UnitPrice,od.Quantity,od.Discount  */
         FROM 
            [Order Details] od 
         WHERE 
            exists (select null from dbo.Orders  innerOrds where innerOrds.OrderID = od.OrderID and innerOrds.CustomerID = @CustomerID )
         ORDER BY 
            od.OrderID 

    END

    SET NOCOUNT OFF


END

GO 
/* Get everything */


exec dbo.uspOrderDetailsByCustomerId 'ALFKI'




    IF OBJECT_ID('tempdb..#TempCustomer') IS NOT NULL
    begin
            drop table #TempCustomer
    end


    CREATE TABLE #TempCustomer
    ( 
      [CustomerID] nchar(5)
    , [CompanyName] nvarchar(40)
    )

INSERT INTO #TempCustomer ( [CustomerID] , [CompanyName])
exec dbo.uspOrderDetailsByCustomerId 'ALFKI' , 1

Select * from #TempCustomer



    IF OBJECT_ID('tempdb..#TempOrders') IS NOT NULL
    begin
            drop table #TempOrders
    end


    CREATE TABLE #TempOrders
    ( 
        OrderID int
      , [CustomerID] nchar(5)

    )

INSERT INTO #TempOrders ( OrderID , [CustomerID] )
exec dbo.uspOrderDetailsByCustomerId 'ALFKI' , 2

Select * from #TempOrders






    IF OBJECT_ID('tempdb..#TempOrderDetails') IS NOT NULL
    begin
            drop table #TempOrderDetails
    end


    CREATE TABLE #TempOrderDetails
    ( 
        OrderID int
      , [ProductID] int

    )

INSERT INTO #TempOrderDetails ( OrderID , [ProductID] )
exec dbo.uspOrderDetailsByCustomerId 'ALFKI' , 3

Select * from #TempOrderDetails


    IF OBJECT_ID('tempdb..#TempOrderDetails') IS NOT NULL
    begin
            drop table #TempOrders
    end


    IF OBJECT_ID('tempdb..#TempOrders') IS NOT NULL
    begin
            drop table #TempOrders
    end



    IF OBJECT_ID('tempdb..#TempCustomer') IS NOT NULL
    begin
            drop table #TempCustomer
    end
4
ответ дан granadaCoder 16 August 2018 в 11:17
поделиться
  • 1
    Это интересная идея, спасибо. Немного хакерский, как вы упоминаете, но похоже, что это сработает. – Joe Enos 20 November 2013 в 22:40
  • 2
    Я использовал его один раз, на некотором коде, который я унаследовал. Я не рекомендую его в качестве лучшей практики. Но это работает. – granadaCoder 20 November 2013 в 22:48
  • 3
    Ах ... Я вижу, что ты там делал. Определенно поможет мне выйти из трудного места, где мне нужен только доступ к одному результирующему набору из специального места. – Jaans 5 February 2016 в 16:01

Создайте SqlDataAdapter, установите его SelectCommand для выполнения SP «GetSomething», а затем используйте адаптер данных для заполнения DataSet. DataSet будет содержать столько же данных DataTable, сколько у вас есть «select», которые возвращают набор записей из SP.

Вот как выглядит ваш код:

System.Data.SqlClient.SqlDataAdapter da = new System.Data.SqlClient.SqlDataAdapter();
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
cmd.Connection = myConnectionObject;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "GetSomething";
da.SelectCommand = cmd;

System.Data.DataSet ds = new DataSet();
da.Fill(ds);
// at this point, the (ds) object contains DataTables created from the recordsets returned by the SP
DataTable dt0 = ds.Tables[0];
DataTable dt1 = ds.Tables[1];

// note that dt0 corresponds to the FIRST recordset returned by the SP, etc.
0
ответ дан Olivier RASSI 16 August 2018 в 11:17
поделиться
String myConnString  = "User ID="username";password="password";Initial Catalog=pubs;Data Source=Server";
SqlConnection myConnection = new SqlConnection(myConnString);
SqlCommand myCommand = new SqlCommand();
SqlDataReader myReader ;

myCommand.CommandType = CommandType.StoredProcedure;
myCommand.Connection = myConnection;
myCommand.CommandText = "MyProc";

try
{
    myConnection.Open();
    myReader = myCommand.ExecuteReader();

    while (myReader.Read())
    {
        //Write logic to process data for the first result.   
        }

    myReader.NextResult();
    while (myReader.Read())
    {
        //Write logic to process data for the second result.
    }
}
8
ответ дан Romasz 16 August 2018 в 11:17
поделиться
  • 1
    myReader.NextResult (); // возвращает данные второго результата – Mahesh Gaikwad 18 December 2014 в 10:59

Хотя это, похоже, не поддерживается в T-SQL изначально, если вы используете хранимую процедуру CLR для вас, то вы должны иметь возможность создать хранимую процедуру на предпочитаемом языке .Net, который использует функцию SqlDataReader.NextResult(), чтобы перейти к желаемому набору результатов, а затем отправить SqlDataReader обратно через метод SqlPipe.Send(SqlDataReader). Вам просто нужно пройти в SQL для выполнения и желаемый результат, заданный в качестве параметров для этого proc.

Это позволит вам работать с proc как есть, не изменяя его, чтобы отправлять обратно все или только один результирующий набор.

4
ответ дан Solomon Rutzky 16 August 2018 в 11:17
поделиться
  • 1
    Спасибо - не большой поклонник CLR procs только потому, что они больно работать, но это звучит как интересный подход. – Joe Enos 20 November 2013 в 22:43

Der. Прочтите весь вопрос, прежде чем писать ответ! :-P

Если вы пытаетесь работать с результатами на земле TSQL, вам нужно будет каким-то образом сохранить результаты отдельно. Написание результатов для таблиц Temp - это, пожалуй, лучший выбор, поскольку вам не нужно будет зависеть от выравнивания столбцов (или нет, в зависимости от ситуации) и может обрабатывать данные «естественным» способом для SQL Server. Например,

create proc test_something
as begin
    select a, b into temp1 from table1
    select b, c into temp2 from table2
end
go

exec dbo.test_something()

select * from temp1
select * from temp2
1
ответ дан Steve G 16 August 2018 в 11:17
поделиться
  • 1
    Это не будет работать, если temp1 и temp2 не будут созданы вне proc, прежде чем будет вызван proc. Временные таблицы, созданные в подпроцессе, удаляются при возврате в вызывающий процесс. – Solomon Rutzky 20 November 2013 в 21:11
  • 2
    Это работает для меня в SQL Server 2008. Нет необходимости создавать temp1 и temp2 за пределами proc, так как они не являются фактически temp-таблицами, это реальные таблицы. Конечно, теперь вам нужно убираться после себя ... И, как всегда, YMMV. :) – Steve G 4 December 2013 в 22:20
Другие вопросы по тегам:

Похожие вопросы: