Cross Apply,Outer Apply
Apply运算符是sql Server 2005及之后版本新加的功能,是T-sql特有的,不是ANSI标准运算符。
Apply:
把右表表达式应用于左输入中的每一行。
右表达式可以引用左输入中的列,对于左表中的每一行都要计算一次右边输入的表达式。
create table customers
(customerid char(5) not null primary key,
cityvarchar(10) not null
)
create table orders
(orderidint not null primary key,
customerid char(5) null
)
go
insert into customers
select 'FISSA','Madrid'
union
select 'FENDO','Madrid'
union
select 'KRLOS','Madrid'
union
select 'MRPHS','Zion'
insert into orders
select 1,'FRNDO'
union
select 2,'FRNDO'
union
select 3,'KRLOS'
union
select 4,'KRLOS'
union
select 5,'KRLOS'
union
select 6,'MRPHS'
union
select 7,null
go
Example:
为每个客户返回具有最大订单的两个订单
select c.customerid,c.city,A.Orderid
from customers as c
cross apply (select top (2) o.orderid,o.customerid from orders as o where o.customerid=c.customerid order by orderid desc) as A
from customers as c
Outer apply (select top (2) o.orderid,o.customerid from orders as o where o.customerid=c.customerid order by orderid desc) as A
使用FOR XML AUTO控制XML输出
这篇文章描述如何通过使用FORXML AUTO更好的控制XML输出格式。例如添加XML标记。用这个来替代难于理解的FORXML EXPLICIT语句。如果你在应用程序中即将反序列化输出的XML,你就会觉得这个信息对你有用。
在For XML从句中,您通常使用下列方式之一:
RAW
AUTO
EXPLICIT
PATH
如果你想完全掌控产生的XML,可以使用FORXML EXPLICIT。但是它理解起来相当的困难,后面还要维护复杂的select语句。FORXML AUTO能产生最可读的SELECT语句,但是它也有缺点,不容易控制生成的XML。但使用一些技巧,例如通过使用额外的PATH选项,你可以做一些超过你预期的事情。RAW选项是很少使用,因此不讨论。PATH选项允许您很容易地混合属性和元素。现在,让我们来使用FORXML AUTO。
在这个例子中,我们使用的是1:N关系的两个简单的数据表。一个表(SalesOrder)包含客户信息的订单,例外一张表(Items)中包含的具体的项。一个订单可以有多个项,一个项往往只属于一个订单。
以最容易的开始。
产生:
-------------------------------------
1 parkerfirstav
2lesleysecav
如果你想要使结果集是XML,我们添加FORXML AUTO语句:
它产生:
<salesorderordernumber="2"customername="lesley"customerstreet="secav"/>
现在,字段是作属性的,大多数情况下希望他们是元素。为了做到这点,添加ELEMENTS参数
它产生:
<ordernumber>1</ordernumber>
<customername>parker</customername>
</salesorder>
如果你想要更改'salesorder
' 标签,使用:
它产生:
<ordernumber>1</ordernumber>
<customername>parker</customername>
</niceorder>
当然,这一招也适用的列名:
它产生:
<order_no>1</order_no>
</salesorder>
如果你想添加其他标签或节点?例如,对有关客户信息添加'customer''标记?但对FOR XML AUTO来说,被证明是很困难的事件。一个可能的解决方案是使用SELF JOIN(join相同的表),但我找到一个更容易办法。经过一番摆弄和修订,我们使用子查询和有点滥用FOR XML PATH命令。
ordernumber,
(SELECT customername,
customerstreetFORXMLPATH('' ),
TYPE,ELEMENTS)
as customer
FROM
salesorder
FORXMLAUTO,ELEMENTS
它产生:
<ordernumber>1</ordernumber>
<customer>
<customername>parker</customername>
<customerstreet>firstav</customerstreet>
</customer>
</salesorder>
<salesorder>
<ordernumber>2</ordernumber>
<customer>
<customername>lesley</customername>
<customerstreet>secav</customerstreet>
</customer>
</salesorder>
注意使用附加的'TYPE’参数。这将确保子查询的结果将返回的是一个XML类型(作为整个XML类型的结果的一部分),而不是NVARCHAR(MAX)类型。如果您要对整个结果添加外围标签,也是简单的小把戏:
SELECT
customername
FROM
salesorder
FOR XMLAUTO,TYPE,ELEMENTS
)ASorderrequestFORXMLPATH(''),ELEMENTS
它产生:
<salesorder>
<customername>parker</customername>
</salesorder>
<salesorder>
<customername>lesley</customername>
</salesorder>
</orderrequest>
为什么我们在子查询中不使用FOR XML AUTO?试试,它会产生一个错误。当子查询是查询一个实际的表时,您才能使用FOR XML AUTO(上述显然不是)。
如果您想对所生产的XML完全控制,子查询是条出路。比方说,我们希望,每个订单,客户的名字和所有的项都属于订单。为此,您使用这样的相关子查询:
customername,
( SELECT*FROMitemWHEREitem.ordernumber=
salesorder.ordernumberFOR XMLAUTO,ELEMENTS)
FROM
salesorder
FORXMLAUTO,ELEMENTS
它产生:
<customername>parker</customername>
<item>
<itemnumber>10</itemnumber>
<description>pen</description>
<ordernumber>1</ordernumber>
</item>
<item>
<itemnumber>11</itemnumber>
<description>paper</description>
<ordernumber>1</ordernumber>
</item>
</salesorder>
当使用关联子查询,你可以使用规则的FOR XML AUTO,ELEMENTS语句。如果你想要在'items'外围有一个标签,只需在子查询后添加as,例如:
customername,
( SELECT*FROMitemWHEREitem.ordernumber=
salesorder.ordernumberFOR XMLAUTO,ELEMENTS)
AS orderitems
FROM
salesorder
FORXMLAUTO,ELEMENTS
它产生:
<customername>parker</customername>
<orderitems>
<item>
<itemnumber>10</itemnumber>
<description>pen</description>
<ordernumber>1</ordernumber>
</item>
<item>
<itemnumber>11</itemnumber>
<description>paper</description>
<ordernumber>1</ordernumber>
</item>
</orderitems>
</salesorder>
为什么我们不只是简单的连接item表和order表。这有时会导致不必要的和不可预测的情况,涉及到产生XML布局:
例如:
item.description,
salesorder.customername
FROM
salesorder
INNERJOINitemONitem.ordernumber= salesorder.ordernumber
FORXMLAUTO,ELEMENTS
会产生这样的垃圾:
<description>pen</description>
<salesorder>
<customername>parker</customername>
</salesorder>
</item>
<item>
<description>paper</description>
<salesorder>
<customername>parker</customername>
</salesorder>
</item>
根据以上解决一些问题会变得很容易:
SELECT [values]= STUFF(REPLACE(REPLACE(
(
SELECT value FROM tbinfo N
WHERE id = A.id
FOR XML AUTO
),'<N value="',','),'"/>',''),1,'')
)N
SELECT * FROM
(SELECT DISTINCT PointCode,
BillCode
FROM T_TY_PayMentDetail WITH(NOLOCK)) A
OUTER APPLY
(SELECT [PayWay]=
STUFF(REPLACE(REPLACE((SELECT Payway as PayWay
FROM T_TY_PayMentDetail N WITH(NOLOCK)
WHERE PointCode = A.PointCode
AND BillCode = a.BillCode
GROUP BY PayWay FOR XML AUTO),'<N PayWay="',';'),'') )N
WHERE (PointCode IN (SELECT PointCode FROM F_GetRelationPointCollection('0',-1 * ISNULL(0,0),1)))
都是解决函数聚合的问题:
YYYY/MM/DD Select Convert(varchar(10),Getdate(),111) --YYYYMMDD Select Convert(varchar(10),112) --HH:MM:SS Select Convert(varchar(8),108) --HH:MM:SS:mmm Select Convert(varchar(12),114)