我正在使用SQL Server 12 / Azure并且有3个表(T1,T2,T3),其中T1有1个多用T2和T3,我想从T2中选择并返回T1记录及其相关T3的信息记录。 举一个简单的例子,T1是"客户",T1是"订单",T3是" CustomerAddresses",因此客户可以有许多订单和多个地址。现在我想查询订单并包括客户信息和地址,使事情有点复杂,订单查询可能包括匹配客户地址,例如获取这些地址的订单。
Customer Table
----------------------
Id, Name,...
----------------------
Orders Table
------------------------------
OrderId, CustomerKey, Date,...
------------------------------
CustomerAddresses
-----------------------------------------------
AutoNumber, CustomerKey, Street, ZipCode,...
-----------------------------------------------
我无法编写最佳方法(优化)以在一个事务中返回所有结果并动态生成sql语句,这就是我认为结果应该回来的方式:
在一个结果集/表中返回订单(T2)和客户信息(T1),并在另一个结果集/表中返回CustomerAddresses(T2)。我使用ADO.NET生成并执行查询,并使用System.Data.SqlClient.SqlDataReader循环返回结果。
结果如何回归的示例:
Order-Customer Table
-------------------------------
Order.OrderId, Customer.Id, Customer.Name, Order.Date,....
-------------------------------
CustomerAddresses
-------------------------------
AutoNumber, CustomerKey, Street
-------------------------------
这是我当前生成的查询示例:
SELECT [Order].[OrderId], [Order].[Date], [Customer].[Id], [Customer].[Name]
FROM Order
INNER JOIN [Customer] on [Order].[CustomerKey] = [Customer].[Id]
WHERE ([Order].[Date] > '2015-06-28')
问题: 1.如何扩展上述查询以允许在单独的结果集/表中返回CustomerAddresses? 要在CustomerAddresses上启用匹配,我应该能够与Customer表进行连接,并在WHERE语句中包含我需要匹配的任何列。
-------- UPDATE --------------- 要详细说明我如何在我的应用中使用返回的数据:
我正在使用ADO.NET,SqlConnection,SqlCommand和SqlDataReader来解析结果。 (我不想在这里使用Entity Framework或任何其他高级DB Framework)
我的模型对象是T2(订单)的集合,其中包含T1(客户信息)和T3(客户地址)
OrderClass: OrderId,OrderDate,CustomerId,CustomerName,CustomerAddresses [],...
CustomerAddresses类: Street,ZipCode,....
我发现人们通常会在一个表中的一个select语句中返回所有结果,这会返回一个冗余数据。我更喜欢按原样返回表格(T1,T2和T3),只包含相关信息,然后我可以在我的应用程序中处理它以创建模型。
另一个解决方案是将select语句中的ID插入Temp表中,然后在多个select语句中返回结果:
Select T1.* From T1 where Id in (
select Temp.T1Id from Temp )
Select T2.* From T2 where Id in (
select Temp.T2Id from Temp )
Select T3.* From T3 where Id in (
select Temp.T3Id from Temp )
答案 0 :(得分:1)
这是一个很好的问题,是一个在其他地方显然没有得到很好解决的常见问题。正如您所提到的,问题在于,由于每个客户可能有许多订单和地址,因此单个查询中的结果数量可能很大。例如,
select * from customer
left outer join order
on (order.customer_id = customer.customer_id)
left outer join customer_orders co
on (co.customer_id = customer.customer_id)
将生成您需要的信息,但会返回许多结果。例如,如果每个客户有n个订单,每个客户有m个地址,则会有mxn结果。
因此,您也提到的方法是一种很好的方法。你所说的是从第一个查询中获取customer_ids,并使用这些id来“生成”订单查询和地址查询。
基本上你需要发出的问题是:
select * from customer
where ....
检索客户信息。然后
select * from order
where customer_id in [The customer_ids found in the above query]
和
select * from customer_address
where customer_id in [The customer_ids found in the above query]
您可以按照建议使用临时表,但是表值参数会更有效。由于您使用的是SQL Server 12,因此可以使用表值参数。有关详细信息,请参阅以下链接:http://www.sommarskog.se/arrays-in-sql-2008.html
所有这些查询都应该在一个事务中完成,您需要注意事务隔离级别,这会使问题进一步复杂化。
答案 1 :(得分:0)
好的,首先关闭......对您来说会更容易,并建议您使用SQL逻辑创建存储过程 ' [DBO] [GetOrderDetails]'
原因是为了防止陷入SQL注入的受害者,并防止重新编译和重新分发您的程序集,直到您的查询更新。
以下是一些解释伪代码来指导您:
public class GpsService extends Service {
private BroadcastReceiver mGpsReceiver;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
registerReceiver();
return Service.START_NOT_STICKY;
}
private void registerReceiver() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO) {
IntentFilter mIntentFilter = new IntentFilter();
mIntentFilter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION);
this.mGpsReceiver = new GpsReceiver();
this.registerReceiver(this.mGpsReceiver, mIntentFilter);
}
}
}
然后从解释的环境转移到托管(编译)代码,您需要查看:
SqlDataReader的:NextResult()
此方法将数据读取器推进到下一个结果集,如下面的伪代码块所示。
CREATE PROCEDURE [dbo].[OrderDetails]
(
@OrderDate DateTime,
@AddressFilter VARCHAR(128)
)
AS
BEGIN
IF(OBJECT_ID('tempdb..#OrderDetails') IS NOT NULL) DROP TABLE #OrderDetails
SELECT orders.[*ListYourOrdersColumnsHere*], customer.[*ListYourCustomerColumnsHere*], addresses.[*ListYourAddressColumnsHere*]
INTO #OrderDetails
FROM [Order] orders
INNER JOIN [Customer] customer on orders.[CustomerKey] = customer.[Id]
LEFT JOIN [CustomerAddresses] addresses ON addresses.[CustomerKey] = customer.[CustomerKey]
-- Or inner join if you need orders just with CustomerAddresses
--INNER JOIN [CustomerAddresses] addresses ON addresses.[CustomerKey] = customer.[CustomerKey]
WHERE orders.[Date] > @OrderDate
AND addresses.StreetName LIKE '%' + @AddressFilter + '%'
-- Orders
SELECT [*ListYourOrdersColumnsHere*]
FROM #OrderDetails
GROUP BY [*ListYourOrdersColumnsHere*]
-- Customers
SELECT [*ListYourCustomerColumnsHere*]
FROM #OrderDetails
GROUP BY [*ListYourCustomerColumnsHere*]
-- Addresses
SELECT [*ListYourAddressColumnsHere*]
FROM #OrderDetails
GROUP BY [*ListYourAddressColumnsHere*]
DROP TABLE #OrderDetails
END
最后,这也可以使用SqlDataAdapter来完成,它将把存储过程作为3个单独的DataTable返回。 Here是文档的链接。
希望这有帮助!