<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_study log</title><subtitle type="text"/><id>http://feed.cnblogs.com/blog/u/23983/rss</id><updated>2012-01-01T05:59:31Z</updated><author><name>lin-zhang</name><uri>http://www.cnblogs.com/michael-zhang/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/michael-zhang/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/23983/rss"/><entry><id>http://www.cnblogs.com/michael-zhang/archive/2012/01/01/2309431.html</id><title type="text">HTML5 &amp;amp; js</title><summary type="text">Table of Contents HTML5 Overview.. 2 Canvas 2D drawing, interactive. 3 Js animation &amp; async. 4 Js class, ‘delegate’ &amp; Inheritance. 5 HTML5 Overview HTML5 ~= HTML + C...</summary><published>2012-01-01T05:49:00Z</published><updated>2012-01-01T05:49:00Z</updated><author><name>lin-zhang</name><uri>http://www.cnblogs.com/michael-zhang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/michael-zhang/archive/2012/01/01/2309431.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/michael-zhang/archive/2012/01/01/2309431.html"/><content type="html">&lt;html&gt;     &lt;head&gt;         &lt;meta http-equiv="Content-Type" content="text/html; charset=gb2312" /&gt;         &lt;meta name="Generator" content="Microsoft Word 12 (filtered)" /&gt;&lt;style&gt; &lt;!         -- /* Font Definitions */ @         font-face         {         font-family: 宋体;         panose-1: 2 1 6 0 3 1 1 1 1 1;         }         @font-face         {         font-family: "Cambria Math";         panose-1: 2 4 5 3 5 4 6 3 2 4;         }         @font-face         {         font-family: Cambria;         panose-1: 2 4 5 3 5 4 6 3 2 4;         }         @font-face         {         font-family: Calibri;         panose-1: 2 15 5 2 2 2 4 3 2 4;         }         @font-face         {         font-family: "\@宋体";         panose-1: 2 1 6 0 3 1 1 1 1 1;         }         /* Style Definitions */p.MsoNormal, li.MsoNormal, div.MsoNormal         {         margin: 0cm;         margin-bottom: .0001pt;         text-align: justify;         text-justify: inter-ideograph;         font-size: 10.5pt;         font-family: "Calibri" , "sans-serif";         }         h1         {         mso-style-link: "Heading 1 Char";         margin-top: 17.0pt;         margin-right: 0cm;         margin-bottom: 16.5pt;         margin-left: 0cm;         text-align: justify;         text-justify: inter-ideograph;         line-height: 240%;         page-break-after: avoid;         font-size: 22.0pt;         font-family: "Calibri" , "sans-serif";         }         h2         {         mso-style-link: "Heading 2 Char";         margin-top: 13.0pt;         margin-right: 0cm;         margin-bottom: 13.0pt;         margin-left: 0cm;         text-align: justify;         text-justify: inter-ideograph;         line-height: 173%;         page-break-after: avoid;         font-size: 16.0pt;         font-family: "Cambria" , "serif";         }         p.MsoToc1, li.MsoToc1, div.MsoToc1         {         margin: 0cm;         margin-bottom: .0001pt;         text-align: justify;         text-justify: inter-ideograph;         font-size: 10.5pt;         font-family: "Calibri" , "sans-serif";         }         p.MsoToc2, li.MsoToc2, div.MsoToc2         {         margin-top: 0cm;         margin-right: 0cm;         margin-bottom: 5.0pt;         margin-left: 11.0pt;         line-height: 115%;         font-size: 11.0pt;         font-family: "Calibri" , "sans-serif";         }         p.MsoToc3, li.MsoToc3, div.MsoToc3         {         margin-top: 0cm;         margin-right: 0cm;         margin-bottom: 5.0pt;         margin-left: 22.0pt;         line-height: 115%;         font-size: 11.0pt;         font-family: "Calibri" , "sans-serif";         }         a:link, span.MsoHyperlink         {         color: blue;         text-decoration: underline;         }         a:visited, span.MsoHyperlinkFollowed         {         color: purple;         text-decoration: underline;         }         p.MsoAcetate, li.MsoAcetate, div.MsoAcetate         {         mso-style-link: "Balloon Text Char";         margin: 0cm;         margin-bottom: .0001pt;         text-align: justify;         text-justify: inter-ideograph;         font-size: 8.0pt;         font-family: "Calibri" , "sans-serif";         }         p.MsoTocHeading, li.MsoTocHeading, div.MsoTocHeading         {         margin-top: 24.0pt;         margin-right: 0cm;         margin-bottom: 0cm;         margin-left: 0cm;         margin-bottom: .0001pt;         line-height: 115%;         page-break-after: avoid;         font-size: 14.0pt;         font-family: "Cambria" , "serif";         color: #365F91;         font-weight: bold;         }         span.Heading1Char         {         mso-style-name: "Heading 1 Char";         mso-style-link: "Heading 1";         font-weight: bold;         }         span.Heading2Char         {         mso-style-name: "Heading 2 Char";         mso-style-link: "Heading 2";         font-family: "Cambria" , "serif";         font-weight: bold;         }         span.apple-style-span         {         mso-style-name: apple-style-span;         }         span.apple-converted-space         {         mso-style-name: apple-converted-space;         }         span.BalloonTextChar         {         mso-style-name: "Balloon Text Char";         mso-style-link: "Balloon Text";         }         /* Page Definitions */@page Section1         {         size: 595.3pt 841.9pt;         margin: 72.0pt 90.0pt 72.0pt 90.0pt;         layout-grid: 15.6pt;         }         div.Section1         {         page: Section1;         }         -- &gt;&lt;/style&gt;     &lt;/head&gt;     &lt;body lang="ZH-CN" link="blue" vlink="purple" style='text-justify-trim: punctuation'&gt;         &lt;div class="Section1" style='layout-grid: 15.6pt'&gt;         &lt;p class="MsoTocHeading"&gt;&lt;span lang="EN-US"&gt;Table of Contents&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoToc1"&gt;&lt;span lang="EN-US"&gt;&lt;a href="#_Toc309058913"&gt;HTML5 Overview&lt;span style='color: windowtext;         display: none; text-decoration: none'&gt;.. &lt;/span&gt;&lt;span style='color: windowtext; display: none;         text-decoration: none'&gt;2&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoToc1"&gt;&lt;span lang="EN-US"&gt;&lt;a href="#_Toc309058914"&gt;Canvas 2D drawing, interactive&lt;span style='color: windowtext;         display: none; text-decoration: none'&gt;. &lt;/span&gt;&lt;span style='color: windowtext; display: none;         text-decoration: none'&gt;3&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoToc1"&gt;&lt;span lang="EN-US"&gt;&lt;a href="#_Toc309058915"&gt;Js animation &amp;amp; async&lt;span style='color: windowtext;         display: none; text-decoration: none'&gt;. &lt;/span&gt;&lt;span style='color: windowtext; display: none;         text-decoration: none'&gt;4&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoToc1"&gt;&lt;span lang="EN-US"&gt;&lt;a href="#_Toc309058916"&gt;Js class, &amp;#8216;&lt;em&gt;delegate&lt;/em&gt;&amp;#8217; &amp;amp; Inheritance&lt;span         style='color: windowtext; display: none; text-decoration: none'&gt;. &lt;/span&gt;&lt;span style='color: windowtext;         display: none; text-decoration: none'&gt;5&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;span lang="EN-US" style='font-size: 10.5pt; font-family: "Calibri","sans-serif"'&gt;&lt;br clear="all" style='page-break-before: always' /&gt;         &lt;/span&gt;         &lt;p class="MsoNormal" align="left" style='text-align: left'&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p&gt;&lt;strong&gt;&lt;a name="_Toc309058913"&gt;&lt;span lang="EN-US"&gt;HTML5 Overview&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://dev.w3.org/html5/spec/Overview.html"&gt;HTML5&lt;/a&gt; ~= &lt;a href="http://en.wikipedia.org/wiki/HTML5"&gt;HTML&lt;/a&gt; + &lt;a href="http://en.wikipedia.org/wiki/CSS3#CSS_3"&gt;CSS&lt;/a&gt; + &lt;a href="http://en.wikipedia.org/wiki/JavaScript"&gt;Javascript&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;New features: Offline storage database, Realtime Communication, Drag-and-drop,         Graphics, Multimedia, &lt;a href="http://en.wikipedia.org/wiki/WebGL"&gt;WebGL&lt;/a&gt;&amp;#8230;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Organization &amp; Standards: &lt;a href="http://en.wikipedia.org/wiki/WHATWG"&gt;WHATWG&lt;/a&gt;(HTML5), &lt;a href="http://en.wikipedia.org/wiki/W3C"&gt;W3C&lt;/a&gt;(CSS, HTML, XML, SOAP, ...), &lt;a href="http://en.wikipedia.org/wiki/Ecma_International"&gt;ECMA&lt;/a&gt;(&lt;a href="http://en.wikipedia.org/wiki/ECMAScript"&gt;ECMAScript&lt;/a&gt;, CLI, ...)&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://slides.html5rocks.com/"&gt;http://slides.html5rocks.com/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Browser Supports:&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://findmebyip.com/litmus/"&gt;http://findmebyip.com/litmus/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://html5test.com/"&gt;http://html5test.com/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Video/Audio Supports:&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://diveintohtml5.info/video.html"&gt;http://diveintohtml5.info/video.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://en.wikipedia.org/wiki/HTML5_video"&gt;http://en.wikipedia.org/wiki/HTML5_video&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Media Capture:&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.w3.org/TR/html-media-capture/"&gt;http://www.w3.org/TR/html-media-capture/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/video-conferencing-and-peer-to-peer-communication.html"&gt;http://www.whatwg.org/specs/web-apps/current-work/multipage/video-conferencing-and-peer-to-peer-communication.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.taboca.com/p/camcanvas/"&gt;http://www.taboca.com/p/camcanvas/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;vs Flash/Silverlight/.. :&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.apple.com/hotnews/thoughts-on-flash/"&gt;Thoughts on Flash (Steve Jobs, 2010.4)&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://en.wikipedia.org/wiki/Comparison_of_HTML5_and_Flash"&gt;http://en.wikipedia.org/wiki/Comparison_of_HTML5_and_Flash&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.zdnet.com/blog/microsoft/will-there-be-a-silverlight-6-and-does-it-matter/11180"&gt;Will there be a Silverlight 6 (and does it matter)?&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.zdnet.com/blog/microsoft/microsoft-our-strategy-with-silverlight-has-shifted/7834?tag=content;siu-container"&gt; Microsoft&amp;#8217;s strategy with Silverlight shifted&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Mobile Browser Supports:&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://en.wikipedia.org/wiki/HTML5_in_mobile_devices"&gt;http://en.wikipedia.org/wiki/HTML5_in_mobile_devices&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://jquerymobile.com/"&gt;http://jquerymobile.com/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://phonegap.com/"&gt;http://phonegap.com/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Graphic Designer:&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://en.wikipedia.org/wiki/Adobe_Edge"&gt;http://en.wikipedia.org/wiki/Adobe_Edge&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.adobe.com/devnet/edge/articles/guide-to-edge.html"&gt;http://www.adobe.com/devnet/edge/articles/guide-to-edge.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Showcase&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.chromeexperiments.com/"&gt;http://www.chromeexperiments.com/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://mugtug.com/sketchpad/"&gt;http://mugtug.com/sketchpad/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://fir.sh/projects/jsnes/"&gt;http://fir.sh/projects/jsnes/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;#8230;&lt;/span&gt;&lt;/p&gt;         &lt;span lang="EN-US" style='font-size: 10.5pt; font-family: "Calibri","sans-serif"'&gt;&lt;br clear="all" style='page-break-before: always' /&gt;         &lt;/span&gt;         &lt;p class="MsoNormal" align="left" style='text-align: left'&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p&gt;&lt;strong&gt;&lt;a name="_Toc309058914"&gt;&lt;span lang="EN-US"&gt;Canvas 2D drawing, interactive&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;API:&amp;nbsp; &lt;a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html"&gt; http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Tutorials:&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://home.cogeco.ca/~ve3ll/jstutorg.htm"&gt;http://home.cogeco.ca/~ve3ll/jstutorg.htm&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://simonsarris.com/blog/225-canvas-selecting-resizing-shape"&gt; http://simonsarris.com/blog/225-canvas-selecting-resizing-shape&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.html5canvastutorials.com/"&gt;http://www.html5canvastutorials.com/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Codes:&lt;a href='#' onclick="javascript:doc = window.open().document; doc.write(document.getElementById('txt2').value); doc.close(); return false;"&gt;Run&lt;/a&gt;&lt;textarea id='txt2' rows="30" cols="90"&gt;&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&amp;quot; &amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;#13;&amp;#10;&amp;lt;html&amp;gt;&amp;#13;&amp;#10;&amp;lt;head&amp;gt;&amp;#13;&amp;#10; &amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;&amp;#13;&amp;#10; #cv1&amp;#13;&amp;#10; {&amp;#13;&amp;#10;/* http://www.colorzilla.com/gradient-editor/ */&amp;#13;&amp;#10;background: #a5c956; /* Old browsers */&amp;#13;&amp;#10;background: -moz-linear-gradient(top, rgba(165,201,86,1) 0%, rgba(205,235,142,1) 100%); /* FF3.6+ */&amp;#13;&amp;#10;background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(165,201,86,1)), color-stop(100%,rgba(205,235,142,1))); /* Chrome,Safari4+ */&amp;#13;&amp;#10;background: -webkit-linear-gradient(top, rgba(165,201,86,1) 0%,rgba(205,235,142,1) 100%); /* Chrome10+,Safari5.1+ */&amp;#13;&amp;#10;background: -o-linear-gradient(top, rgba(165,201,86,1) 0%,rgba(205,235,142,1) 100%); /* Opera 11.10+ */&amp;#13;&amp;#10;background: -ms-linear-gradient(top, rgba(165,201,86,1) 0%,rgba(205,235,142,1) 100%); /* IE10+ */&amp;#13;&amp;#10;background: linear-gradient(top, rgba(165,201,86,1) 0%,rgba(205,235,142,1) 100%); /* W3C */&amp;#13;&amp;#10;filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#a5c956', endColorstr='#cdeb8e',GradientType=0 ); /* IE6-9 */&amp;#13;&amp;#10; }&amp;#13;&amp;#10; &amp;lt;/style&amp;gt;&amp;#13;&amp;#10; &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;#13;&amp;#10; var select1, canv, ctx;&amp;#13;&amp;#10; &amp;#13;&amp;#10; function draw(iScale) {&amp;#13;&amp;#10; ctx.clearRect(0, 0, 700, 400);&amp;#13;&amp;#10; ctx.save();&amp;#13;&amp;#10; ctx.scale(iScale, iScale);&amp;#13;&amp;#10; //ctx.rotate(-Math.PI / 4); //ctx.rotate(-Math.PI * 2);&amp;#13;&amp;#10;&amp;#13;&amp;#10; ctx.fillStyle = &amp;quot;#c80000&amp;quot;;&amp;#13;&amp;#10; ctx.fillRect(10, 20, 50, 50);&amp;#13;&amp;#10; ctx.fillStyle = &amp;quot;rgba(0,0,200,0.5)&amp;quot;;&amp;#13;&amp;#10; ctx.fillRect(30, 40, 50, 50);&amp;#13;&amp;#10; ctx.strokeStyle = '#fff';&amp;#13;&amp;#10; ctx.lineWidth = 2;&amp;#13;&amp;#10; ctx.strokeRect(30, 40, 50, 50);&amp;#13;&amp;#10;&amp;#13;&amp;#10; ctx.font = '2em sans-serif';&amp;#13;&amp;#10; ctx.textBaseline = 'top';&amp;#13;&amp;#10; ctx.lineWidth = 1;&amp;#13;&amp;#10; ctx.fillStyle = '#000';&amp;#13;&amp;#10; ctx.strokeStyle = '#fff';&amp;#13;&amp;#10; ctx.fillText('Canvas', 120, 10);&amp;#13;&amp;#10; ctx.strokeText('2D Drawing', 240, 10);&amp;#13;&amp;#10;&amp;#13;&amp;#10; ctx.beginPath();&amp;#13;&amp;#10; ctx.arc(200, 100, 30, 0, Math.PI * 1.5, false);&amp;#13;&amp;#10; ctx.closePath();&amp;#13;&amp;#10; ctx.fill();&amp;#13;&amp;#10;&amp;#13;&amp;#10; ctx.beginPath();&amp;#13;&amp;#10; ctx.arc(300, 100, 30, 0, Math.PI * 2, true);&amp;#13;&amp;#10; ctx.closePath();&amp;#13;&amp;#10; ctx.stroke();&amp;#13;&amp;#10;&amp;#13;&amp;#10; ctx.strokeStyle = '#000';&amp;#13;&amp;#10; ctx.beginPath();&amp;#13;&amp;#10; ctx.moveTo(10, 200);&amp;#13;&amp;#10; ctx.lineTo(90, 300);&amp;#13;&amp;#10; ctx.lineTo(90, 200);&amp;#13;&amp;#10; ctx.closePath();&amp;#13;&amp;#10; ctx.stroke();&amp;#13;&amp;#10;&amp;#13;&amp;#10; var img = new Image();&amp;#13;&amp;#10; img.onload = function() {&amp;#13;&amp;#10; var width = 90;&amp;#13;&amp;#10; width *= iScale; //scale image size&amp;#13;&amp;#10; ctx.drawImage(img, 260, 200, width, width);&amp;#13;&amp;#10; };&amp;#13;&amp;#10; img.src = 'http://images.weiphone.com/attachments/Day_090828/22_270438_b871908fc2cccdc.jpg';&amp;#13;&amp;#10;&amp;#13;&amp;#10; ctx.restore();&amp;#13;&amp;#10; }&amp;#13;&amp;#10; window.onload = function() {&amp;#13;&amp;#10; select1 = document.getElementById('sel1');&amp;#13;&amp;#10; for (var i = 0.2; i &amp;lt; 1.6; i += 0.2) {&amp;#13;&amp;#10; select1.add(new Option(i));&amp;#13;&amp;#10; }&amp;#13;&amp;#10; select1.selectedIndex = 4;&amp;#13;&amp;#10; select1['onchange'] = function() {&amp;#13;&amp;#10; var idx = select1.selectedIndex;&amp;#13;&amp;#10; var obj = select1.options[idx];&amp;#13;&amp;#10; draw(obj.innerText);&amp;#13;&amp;#10; };&amp;#13;&amp;#10;&amp;#13;&amp;#10; canv = document.getElementById('cv1');&amp;#13;&amp;#10; ctx = canv.getContext(&amp;quot;2d&amp;quot;);&amp;#13;&amp;#10; canv['onmousemove'] = function(e) {&amp;#13;&amp;#10; document.getElementById('txt1').value = (e.clientX - canv.offsetLeft) + ',' + (e.clientY - canv.offsetTop);&amp;#13;&amp;#10; }&amp;#13;&amp;#10;&amp;#13;&amp;#10; draw(1);&amp;#13;&amp;#10; }&amp;#13;&amp;#10; &amp;lt;/script&amp;gt;&amp;#13;&amp;#10;&amp;lt;/head&amp;gt;&amp;#13;&amp;#10;&amp;lt;body&amp;gt;&amp;#13;&amp;#10; &amp;lt;div&amp;gt;Scale: &amp;lt;select id='sel1'&amp;gt;&amp;lt;/select&amp;gt;&amp;amp;nbsp;Mouse Position:&amp;lt;input type='text' id='txt1' /&amp;gt;&amp;lt;/div&amp;gt;&amp;#13;&amp;#10; &amp;lt;canvas id=&amp;quot;cv1&amp;quot; width=&amp;quot;700&amp;quot; height=&amp;quot;400&amp;quot;&amp;gt;Your browser does not support Canvas&amp;lt;/canvas&amp;gt;&amp;#13;&amp;#10;&amp;lt;/body&amp;gt;&amp;#13;&amp;#10;&amp;lt;/html&amp;gt;&lt;/textarea&gt;&lt;/span&gt;&lt;/p&gt;         &lt;span lang="EN-US" style='font-size: 10.5pt; font-family: "Calibri","sans-serif"'&gt;&lt;br clear="all" style='page-break-before: always' /&gt;         &lt;/span&gt;         &lt;p class="MsoNormal" align="left" style='text-align: left'&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p&gt;&lt;strong&gt;&lt;a name="_Toc309058915"&gt;&lt;span lang="EN-US"&gt;Js animation &amp;amp; async&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.w3school.com.cn/htmldom/met_win_setinterval.asp"&gt; setInterval&lt;/a&gt; / &lt;a href="http://www.w3school.com.cn/htmldom/met_win_clearinterval.asp"&gt; clearInterval&lt;/a&gt;, &lt;a href="http://www.w3school.com.cn/htmldom/met_win_settimeout.asp"&gt; setTimeout&lt;/a&gt; / &lt;a href="http://www.w3school.com.cn/htmldom/met_win_cleartimeout.asp"&gt; clearTimeout&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Codes:&lt;a href='#' onclick="javascript:doc = window.open().document; doc.write(document.getElementById('txt3').value); doc.close(); return false;"&gt;Run&lt;/a&gt;&lt;textarea id='txt3' rows="30" cols="90"&gt;&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD XHTML 1.0 Transitional//EN&amp;quot; &amp;quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&amp;quot;&amp;gt;&amp;#13;&amp;#10;&amp;lt;html&amp;gt;&amp;#13;&amp;#10;&amp;lt;head&amp;gt;&amp;#13;&amp;#10; &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;#13;&amp;#10; var ck1, ck2, itv1, itv2, cv1, ctx,x, div2, wid2, hei2;&amp;#13;&amp;#10; var INTERVAL1 = 50, INTERVAL2 = 50;&amp;#13;&amp;#10;&amp;#13;&amp;#10; function animate1() {&amp;#13;&amp;#10; ctx.clearRect(x, 20, 50, 50); //clear previous drawing&amp;#13;&amp;#10; x += 5;&amp;#13;&amp;#10; if (x &amp;gt;= 800) x = 1;&amp;#13;&amp;#10; ctx.fillRect(x, 20, 50, 50);&amp;#13;&amp;#10; }&amp;#13;&amp;#10;&amp;#13;&amp;#10; function animate2() {&amp;#13;&amp;#10; wid2 += 5;&amp;#13;&amp;#10; hei2 += 1.5;&amp;#13;&amp;#10; if (wid2 &amp;gt;= 800) {&amp;#13;&amp;#10; wid2 = hei2 = 1;&amp;#13;&amp;#10; }&amp;#13;&amp;#10; div2.style.width = wid2 + 'px';&amp;#13;&amp;#10; div2.style.height = hei2 + 'px';&amp;#13;&amp;#10;&amp;#13;&amp;#10; itv2 = setTimeout(animate2, INTERVAL2);&amp;#13;&amp;#10; }&amp;#13;&amp;#10;&amp;#13;&amp;#10; window.onload = function() {&amp;#13;&amp;#10; cv1 = document.getElementById('cv1');&amp;#13;&amp;#10; div2 = document.getElementById('div2');&amp;#13;&amp;#10; ck1 = document.getElementById('ck1');&amp;#13;&amp;#10; ck2 = document.getElementById('ck2');&amp;#13;&amp;#10;&amp;#13;&amp;#10; ck1['onchange'] = function() {&amp;#13;&amp;#10; if (ck1.checked)&amp;#13;&amp;#10; itv1 = setInterval(animate1, INTERVAL1);&amp;#13;&amp;#10; else&amp;#13;&amp;#10; clearInterval(itv1);&amp;#13;&amp;#10; };&amp;#13;&amp;#10; ck2['onchange'] = function() {&amp;#13;&amp;#10; if (ck2.checked)&amp;#13;&amp;#10; itv2 = setTimeout(animate2, INTERVAL2);&amp;#13;&amp;#10; else&amp;#13;&amp;#10; clearTimeout(itv2);&amp;#13;&amp;#10; };&amp;#13;&amp;#10;&amp;#13;&amp;#10; wid2 = hei2 = 1;&amp;#13;&amp;#10; x = 1;&amp;#13;&amp;#10; ctx = cv1.getContext(&amp;quot;2d&amp;quot;);&amp;#13;&amp;#10; ctx.fillStyle = &amp;quot;rgba(0,0,200,0.6)&amp;quot;;&amp;#13;&amp;#10; ck1['onchange']();&amp;#13;&amp;#10; ck2['onchange']();&amp;#13;&amp;#10; }&amp;#13;&amp;#10; &amp;lt;/script&amp;gt;&amp;#13;&amp;#10;&amp;lt;/head&amp;gt;&amp;#13;&amp;#10;&amp;lt;body&amp;gt;&amp;#13;&amp;#10; &amp;lt;div&amp;gt;&amp;#13;&amp;#10; &amp;lt;input id='ck1' type='checkbox' checked='checked' /&amp;gt;&amp;lt;label for=&amp;quot;ck1&amp;quot;&amp;gt;enable Animation 1&amp;lt;/label&amp;gt;&amp;#13;&amp;#10; &amp;lt;input id='ck2' type='checkbox' checked='checked' /&amp;gt;&amp;lt;label for=&amp;quot;ck2&amp;quot;&amp;gt;enable Animation 2&amp;lt;/label&amp;gt;&amp;#13;&amp;#10; &amp;lt;/div&amp;gt;&amp;#13;&amp;#10; &amp;lt;canvas id=&amp;quot;cv1&amp;quot; width=&amp;quot;800&amp;quot; height=&amp;quot;100&amp;quot; style=&amp;quot;background-color: Lime; margin-top:20px;&amp;quot;&amp;gt;Your browser does not support Canvas&amp;lt;/canvas&amp;gt;&amp;#13;&amp;#10; &amp;lt;div id='div2' style=&amp;quot;background-color:Olive; position: relative; width:100px; height:100px; margin-top:20px; border: 1px solid black;&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;lt;/div&amp;gt;&amp;#13;&amp;#10;&amp;lt;/body&amp;gt;&amp;#13;&amp;#10;&amp;lt;/html&amp;gt;&lt;/textarea&gt;&lt;/span&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Some Librarys:&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://jqapi.com/#p=animate"&gt;http://jqapi.com/#p=animate&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href="http://jljlpch.iteye.com/blog/234130"&gt;jquery animate&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="https://github.com/JeffreyZhao/jscex"&gt;https://github.com/JeffreyZhao/jscex&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;         &lt;a href="http://www.sndacode.com/projects/jscex/wiki"&gt;http://www.sndacode.com/projects/jscex/wiki&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;         &lt;a href="http://files.zhaojie.me/jscex/samples/async/move.html"&gt;move.html&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;         &lt;a href="http://files.zhaojie.me/jscex/samples/async/sorting-animations.html"&gt; sorting-animations.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.infoq.com/articles/surviving-asynchronous-programming-in-javascript"&gt; http://www.infoq.com/articles/surviving-asynchronous-programming-in-javascript&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.neilmix.com/narrativejs/doc/"&gt;http://www.neilmix.com/narrativejs/doc/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.infoq.com/articles/stratifiedjs"&gt;http://www.infoq.com/articles/stratifiedjs&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;span lang="EN-US" style='font-size: 10.5pt; font-family: "Calibri","sans-serif"'&gt;&lt;br clear="all" style='page-break-before: always' /&gt;         &lt;/span&gt;         &lt;p class="MsoNormal" align="left" style='text-align: left'&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;p&gt;&lt;strong&gt;&lt;a name="_Toc309058916"&gt;&lt;span lang="EN-US"&gt;Js class, &amp;#8216;&lt;em&gt;delegate&lt;/em&gt;&amp;#8217; &amp;amp; Inheritance&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;Codes:&lt;a href='#' onclick="javascript:doc = window.open().document; doc.write(document.getElementById('txt4').value); doc.close(); return false;"&gt;Run&lt;/a&gt;&lt;textarea id='txt4' rows="30" cols="90"&gt;&amp;lt;html&amp;gt;&amp;#13;&amp;#10;&amp;lt;head&amp;gt;&amp;#13;&amp;#10; &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;#13;&amp;#10; // class definition&amp;#13;&amp;#10; function Person(name,gender, age) {&amp;#13;&amp;#10; this.name = name;&amp;#13;&amp;#10; this.gender = gender;&amp;#13;&amp;#10; this.age = age;&amp;#13;&amp;#10;&amp;#13;&amp;#10; this.speak = function() {&amp;#13;&amp;#10; log('this is ' + this.name + ' speaking.');&amp;#13;&amp;#10; }&amp;#13;&amp;#10; }&amp;#13;&amp;#10; Person.prototype.toString = function() {&amp;#13;&amp;#10; return this.name + '(age:' + this.gender + '),' + this.age;&amp;#13;&amp;#10; }&amp;#13;&amp;#10; Person.Parse = function(s) { //static method&amp;#13;&amp;#10; try{&amp;#13;&amp;#10; var ary = s.split(',');&amp;#13;&amp;#10; return new Person(ary[0], ary[1], ary[2]);&amp;#13;&amp;#10; }catch(e){&amp;#13;&amp;#10; return null;&amp;#13;&amp;#10; }&amp;#13;&amp;#10; }&amp;#13;&amp;#10;&amp;#13;&amp;#10; //method use function as argument&amp;#13;&amp;#10; function revealObject(obj, fn) {&amp;#13;&amp;#10; var aryInfo = [];&amp;#13;&amp;#10; for (var k in obj) {&amp;#13;&amp;#10; var s = fn(k, obj[k]);&amp;#13;&amp;#10; if (!s) continue;&amp;#13;&amp;#10; aryInfo.push(s);&amp;#13;&amp;#10; }&amp;#13;&amp;#10; return aryInfo.join('\r\n');&amp;#13;&amp;#10; }&amp;#13;&amp;#10;&amp;#13;&amp;#10; //inheritance&amp;#13;&amp;#10; function Programer(n, g, a, lan) {&amp;#13;&amp;#10; Person.call(this, n, g, a);&amp;#13;&amp;#10; //Person.apply(this, [n, g, a]);&amp;#13;&amp;#10;&amp;#13;&amp;#10; this.language = lan;&amp;#13;&amp;#10; }&amp;#13;&amp;#10; Programer.prototype = new Person;&amp;#13;&amp;#10; Programer.prototype.toString = function() {&amp;#13;&amp;#10; return Person.prototype.toString.call(this) + ' , ' + this.language;&amp;#13;&amp;#10; }&amp;#13;&amp;#10;&amp;#13;&amp;#10; function log(s) {&amp;#13;&amp;#10; document.getElementById('tOutput').value += (s ? s : '') + '\r\n';&amp;#13;&amp;#10; }&amp;#13;&amp;#10;&amp;#13;&amp;#10; window.onload = function() {&amp;#13;&amp;#10; log('class demo\r\n-------------------------------');&amp;#13;&amp;#10; var p1 = new Person('bill', 16, 'male');&amp;#13;&amp;#10; var p2 = Person.Parse('steve,48,male');&amp;#13;&amp;#10; log(p1 + '\r\n' + p2);&amp;#13;&amp;#10; p1.speak();&amp;#13;&amp;#10; p2.speak();&amp;#13;&amp;#10;&amp;#13;&amp;#10; log('\r\ndelegate demo\r\n-------------------------------');&amp;#13;&amp;#10; var f1 = function(s1, s2) { return s1 + ' : ' + s2; };&amp;#13;&amp;#10; var s1 = revealObject(p1, f1);&amp;#13;&amp;#10; log(s1);&amp;#13;&amp;#10; log();&amp;#13;&amp;#10; var s2 = revealObject(p2, function(s1, s2) { if (typeof (s2) == 'function') return ''; return s1 + ',' + s2; });&amp;#13;&amp;#10; log(s2);&amp;#13;&amp;#10;&amp;#13;&amp;#10; log('\r\ninheritance demo\r\n-------------------------------');&amp;#13;&amp;#10; var pg1 = new Programer('kate', 'female', 22, 'C, C++');&amp;#13;&amp;#10; log(pg1);&amp;#13;&amp;#10; }&amp;#13;&amp;#10; &amp;lt;/script&amp;gt;&amp;#13;&amp;#10;&amp;lt;/head&amp;gt;&amp;#13;&amp;#10;&amp;lt;body&amp;gt;&amp;#13;&amp;#10; &amp;lt;textarea id='tOutput' rows='30' cols='90'&amp;gt;&amp;lt;/textarea&amp;gt;&amp;#13;&amp;#10;&amp;lt;/body&amp;gt;&amp;#13;&amp;#10;&amp;lt;/html&amp;gt;&lt;/textarea&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://www.joelonsoftware.com/items/2006/08/01.html"&gt;http://www.joelonsoftware.com/items/2006/08/01.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://mckoss.com/jscript/object.htm"&gt;http://mckoss.com/jscript/object.htm&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://ejohn.org/blog/simple-javascript-inheritance/"&gt;http://ejohn.org/blog/simple-javascript-inheritance/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&lt;a href="http://odetocode.com/blogs/scott/archive/2007/07/05/function-apply-and-function-call-in-javascript.aspx"&gt; http://odetocode.com/blogs/scott/archive/2007/07/05/function-apply-and-function-call-in-javascript.aspx&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;         &lt;p class="MsoNormal"&gt;&lt;span lang="EN-US"&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;         &lt;/div&gt;     &lt;/body&gt;&lt;/html&gt;&lt;img src="http://www.cnblogs.com/michael-zhang/aggbug/2309431.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/michael-zhang/archive/2012/01/01/2309431.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/michael-zhang/archive/2011/07/08/2101031.html</id><title type="text">Concatenating row values in Transact-SQL</title><summary type="text">转自: http://www.projectdmx.com/tsql/rowconcatenate.aspx Concatenating row values in Transact-SQL Introduction A core issue Considerations Concatenating values when the number of items is small and known upfront Concatenating values when the number of items are not known Recursive CTE method The black</summary><published>2011-07-08T07:16:00Z</published><updated>2011-07-08T07:16:00Z</updated><author><name>lin-zhang</name><uri>http://www.cnblogs.com/michael-zhang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/michael-zhang/archive/2011/07/08/2101031.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/michael-zhang/archive/2011/07/08/2101031.html"/><content type="html">&lt;p&gt;&lt;strong&gt;转自&lt;/strong&gt;: &lt;a href="http://www.projectdmx.com/tsql/rowconcatenate.aspx"&gt;http://www.projectdmx.com/tsql/rowconcatenate.aspx&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;table width="100%" cellpadding="0" cellspacing="0" border="0"&gt;     &lt;tbody&gt;         &lt;tr valign="top"&gt;             &lt;td align="center" style="width: 100px"&gt;&lt;/td&gt;             &lt;td align="center"&gt;             &lt;table class="body"&gt;                 &lt;tbody&gt;                     &lt;tr align="left"&gt;                         &lt;td valign="top"&gt;&lt;strong&gt;Concatenating row values in Transact-SQL&lt;/strong&gt;&lt;br /&gt;                         &lt;br /&gt;                         &lt;/td&gt;                     &lt;/tr&gt;                     &lt;tr align="left"&gt;                         &lt;td valign="top"&gt;&lt;strong&gt;                         &lt;ul type="disc"&gt;                             &lt;li&gt;&lt;a href="#Intro"&gt;Introduction&lt;/a&gt;&lt;/li&gt;                             &lt;li&gt;&lt;a href="#Core"&gt;A core issue&lt;/a&gt;&lt;/li&gt;                             &lt;li&gt;&lt;a href="#Consider"&gt;Considerations&lt;/a&gt;&lt;/li&gt;                             &lt;li&gt;&lt;a href="#Limited"&gt;Concatenating values when the number of items is small and known upfront&lt;/a&gt;&lt;/li&gt;                             &lt;li&gt;&lt;a href="#Unlimited"&gt;Concatenating values when the number of items are not known&lt;/a&gt;&lt;/li&gt;                             &lt;ul type="square"&gt;                                 &lt;li&gt;&lt;a href="#RecurCTE"&gt;Recursive CTE method&lt;/a&gt;&lt;/li&gt;                                 &lt;li&gt;&lt;a href="#BBXML"&gt;The blackbox XML methods&lt;/a&gt;&lt;/li&gt;                                 &lt;li&gt;&lt;a href="#UsingCLR"&gt;Using Common Language Runtime&lt;/a&gt;&lt;/li&gt;                                 &lt;li&gt;&lt;a href="#ScalarRecur"&gt;Scalar UDF with recursion&lt;/a&gt;&lt;/li&gt;                                 &lt;li&gt;&lt;a href="#TblUDF"&gt;Table valued UDF with a WHILE loop&lt;/a&gt;&lt;/li&gt;                                 &lt;li&gt;&lt;a href="#DynamicSQL"&gt;Dynamic SQL&lt;/a&gt;&lt;/li&gt;                                 &lt;li&gt;&lt;a href="#Cursor"&gt;The Cursor approach&lt;/a&gt;&lt;/li&gt;                             &lt;/ul&gt;                             &lt;li&gt;&lt;a href="#Unreliable"&gt;Non-reliable approaches&lt;/a&gt;&lt;/li&gt;                             &lt;ul type="square"&gt;                                 &lt;li&gt;&lt;a href="#UpdateExtn"&gt;Scalar UDF with t-SQL update extension&lt;/a&gt;&lt;/li&gt;                                 &lt;li&gt;&lt;a href="#SelectConcat"&gt;Scalar UDF with variable concatenation in SELECT&lt;/a&gt;&lt;/li&gt;                             &lt;/ul&gt;                             &lt;li&gt;&lt;a href="#Concl"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;                             &lt;li&gt;&lt;a href="#Refer"&gt;References&lt;/a&gt;&lt;/li&gt;                             &lt;li&gt;&lt;a href="#Acknow"&gt;Acknowledgements&lt;/a&gt;&lt;/li&gt;                         &lt;/ul&gt;                         &lt;/strong&gt;&lt;/td&gt;                     &lt;/tr&gt;                     &lt;tr&gt;                         &lt;td align="left"&gt;&lt;strong&gt;&lt;a name="#Intro"&gt;&lt;/a&gt;Introduction&lt;/strong&gt;&lt;br /&gt;                         &lt;br /&gt;                         Many a time, SQL programmers are faced with a requirement to generate report-like resultsets right off of a Transact SQL                         query. In most cases, the requirement arises from the fact that there are no sufficient tools or in-house expertise to develop                         tools that can extract the data as a resultset and massage the data in the desired display format. Quite often folks are                         confused about the potential of breaking relational fundamentals say like First Normal Form or the scalar nature of typed                         values. (Talking about 1NF violations in a language like SQL which lacks sufficient domain support, allows NULLs and supports                         duplicates is somewhat ironic to begin with, but that is a topic which requires detailed explanations.)                         &lt;br /&gt;                         &lt;br /&gt;                         Concatenating column values or expressions from multiple rows are usually best done in a client side application language,                         since the string manipulation capabilities of Transact SQL and SQL based DBMSs are somewhat limited. However, you can do these                         using different approaches in Transact SQL, but avoiding such methods for long term solutions is your best bet.                         &lt;br /&gt;                         &lt;br /&gt;                         &lt;strong&gt;&lt;a name="#Core"&gt;&lt;/a&gt;A core issue&lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         Even though SQL in general deviates considerably from the relational model, its reliance on certain core aspects of relational                         foundations makes SQL functional and powerful. One such core aspect is the set based nature of SQL expressions (well, multi-sets                         to be exact, but for the given context let us ignore the issue of duplication). The primary idea is that tables are unordered                         and hence the resultsets of any query that does not have an explicit ORDER BY clause is unordered as well. In other words, the rows                         in a resultset of a query do not have a prescribed position, unless it is explicitly specified in the query expression.                         &lt;br /&gt;                         &lt;br /&gt;                         On the other hand, a concatenated list is an ordered structure. Each element in the list has a specific position. In fact,                         concatenation itself is an order-utilizing operation in the sense that values can be prefixed or post fixed to an existing list. So                         approaches that are loosely called &amp;#8220;concatenating row values&amp;#8221;, &amp;#8220;aggregate concatenation&amp;#8221; etc. would have to make sure that some kind                         of an order, either explicit or implicit, should be specified prior to concatenating the row values. If such an ordering criteria                         is not provided, the concatenated string would be arbitrary in nature.                         &lt;br /&gt;                         &lt;br /&gt;                         &lt;strong&gt;&lt;a name="#Consider"&gt;&lt;/a&gt;Considerations&lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         Generally, requests for row value concatenations often comes in two basic flavors, when the number of rows is known and small (typically                         less than 10) and when the number of rows is unknown and potentially large. It may be better to look at each of them separately.                         &lt;br /&gt;                         &lt;br /&gt;                         In some cases, all the programmer wants is just the list of values from a set of rows. There is no grouping or logical partitioning                         of values like the list of email addresses separated by a semicolon or some such. In such situations, the approaches can be the same                         except the join conditions may vary. Minor variations of the examples list on this page illustrate such solutions as well.                         &lt;br /&gt;                         &lt;br /&gt;                         For the purpose of this article the Products table from Northwind database is used to illustrate column value concatenations with a                         grouping column. Northwind is a sample database in SQL Server 2000 default installations. You can download a copy from from the                         &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=06616212-0356-46a0-8da2-eebc53a68034&amp;amp;displaylang=en"&gt;Microsoft Downloads&lt;/a&gt;                         Consider the resultset produced by the following query:                         &lt;br /&gt;                         &lt;br /&gt;                          SELECT CategoryId, ProductName&lt;br/&gt;                         FROM Northwind..Products ;&lt;br/&gt;                         CategoryId ProductName&lt;br/&gt;                         ----------- ----------------------------------------&lt;br/&gt;                         1 Chai&lt;br/&gt;                         1 Chang&lt;br/&gt;                         ...&lt;br/&gt;                         2 Aniseed Syrup&lt;br/&gt;                         2 Chef Anton's Cajun Seasoning&lt;br/&gt;                         ...&lt;br/&gt;                         ...&lt;br/&gt;                         8 Spegesild&lt;br/&gt;                         (77 row(s) affected)&lt;br/&gt;                                                  The goal is to return a resultset with two columns one with the Category Identifier and the other with a concatenated list of all                         the Product Names separated by a delimiting character, say a comma for instance.                          CategoryId Product List&lt;br/&gt;                         ----------- -----------------------------------------------------------------------------&lt;br/&gt;                         1 Chai, Chang, Chartreuse verte, C&amp;#244;te de Blaye, ...&lt;br/&gt;                         2 Aniseed Syrup, Chef Anton's Cajun Seasoning, ...&lt;br/&gt;                         3 Chocolade, Gumb&amp;#228;r Gummib&amp;#228;rchen, Maxilaku, ...&lt;br/&gt;                         4 Camembert Pierrot, Flotemysost, Geitost, Gorgonzola Telino, ...&lt;br/&gt;                         5 Filo Mix, Gnocchi di nonna Alice, Gustaf's Kn&amp;#228;ckebr&amp;#246;d, ...&lt;br/&gt;                         6 Alice Mutton, Mishi Kobe Niku, P&amp;#226;t&amp;#233; chinois, ...&lt;br/&gt;                         7 Longlife Tofu, Manjimup Dried Apples, R&amp;#246;ssle Sauerkraut, ...&lt;br/&gt;                         8 Boston Crab Meat, Carnarvon Tigers, Escargots de Bourgogne, ...&lt;br/&gt;                         (8 row(s) affected)&lt;br/&gt;                                                  &lt;strong&gt;&lt;a name="#Limited"&gt;&lt;/a&gt;Concatenating values when the number of items is small and known upfront&lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         When the number of rows are small and almost known upfront, it is easier to generate the code. One common approach with a small set                         of finite rows it the pivoting method. Here is an example where only first four alphabetically sorted product names per categoryid is                         retrieved:                          SELECT CategoryId,&lt;br/&gt;                         MAX( CASE seq WHEN 1 THEN ProductName ELSE '' END ) + ', ' +&lt;br/&gt;                         MAX( CASE seq WHEN 2 THEN ProductName ELSE '' END ) + ', ' +&lt;br/&gt;                         MAX( CASE seq WHEN 3 THEN ProductName ELSE '' END ) + ', ' +&lt;br/&gt;                         MAX( CASE seq WHEN 4 THEN ProductName ELSE '' END )&lt;br/&gt;                         FROM ( SELECT p1.CategoryId, p1.ProductName,&lt;br/&gt;                         ( SELECT COUNT(*)&lt;br/&gt;                         FROM Northwind.dbo.Products p2&lt;br/&gt;                         WHERE p2.CategoryId = p1.CategoryId&lt;br/&gt;                         AND p2.ProductName &amp;lt;= p1.ProductName )&lt;br/&gt;                         FROM Northwind.dbo.Products p1 ) D ( CategoryId, ProductName, seq )&lt;br/&gt;                         GROUP BY CategoryId ;&lt;br/&gt;                                                  The idea above is to create a expression inside the correlated subquery that produces a rank (seq) based on the product names and                         then use it in the outer query. Using common table expressions and the ROW_NUMBER() function, you can re-write this as:                         ; WITH CTE ( CategoryId, ProductName, seq )&lt;br/&gt;                         AS ( SELECT p1.CategoryId, p1.ProductName,&lt;br/&gt;                         ROW_NUMBER() OVER ( PARTITION BY CategoryId ORDER BY ProductName )&lt;br/&gt;                         FROM Northwind.dbo.Products p1 )&lt;br/&gt;                         SELECT CategoryId,&lt;br/&gt;                         MAX( CASE seq WHEN 1 THEN ProductName ELSE '' END ) + ', ' +&lt;br/&gt;                         MAX( CASE seq WHEN 2 THEN ProductName ELSE '' END ) + ', ' +&lt;br/&gt;                         MAX( CASE seq WHEN 3 THEN ProductName ELSE '' END ) + ', ' +&lt;br/&gt;                         MAX( CASE seq WHEN 4 THEN ProductName ELSE '' END )&lt;br/&gt;                         FROM CTE&lt;br/&gt;                         GROUP BY CategoryId ;&lt;br/&gt;                                                  Note that ROW_NUMBER() is a newly introduced feature in SQL 2005. If you are using any previous versions, you will have to use the                         subquery approach (You can also use a self-join, to write it a bit differently). Using the recently introduced PIVOT operator, you                         can write the above as following :                          SELECT CategoryId,&lt;br/&gt;                         "1" + ', ' + "2" + ', ' + "3" + ', ' + "4" AS Product_List&lt;br/&gt;                         FROM ( SELECT CategoryId, ProductName,&lt;br/&gt;                         ROW_NUMBER() OVER (PARTITION BY CategoryId ORDER BY ProductName)&lt;br/&gt;                         FROM Northwind.dbo.Products ) P ( CategoryId, ProductName, seq )&lt;br/&gt;                         PIVOT ( MAX( ProductName ) FOR seq IN ( "1", "2", "3", "4" ) ) AS P_ ;&lt;br/&gt;                                                  Not only the syntax appears a bit confusing, it does not appear to offer anything functionally beyond the CASE approach above. However,                         in rare situations, it could come in handy.                         &lt;br /&gt;                         &lt;br /&gt;                         &lt;strong&gt;&lt;a name="#Unlimited"&gt;&lt;/a&gt;Concatenating values when the number of items is not known &lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         When the number of items that are to be concatenated is not known upfront, the code can become a bit more demanding. The new features                         in SQL 2005 make some of the approaches a bit easy. For instance, the recursive common table expressions (CTEs) and the FOR XML PATH('')                         syntax makes the server do the hard work behind the concatenation leaving the programmer to deal with the presentation issues. The                         examples below make this point obvious.                         &lt;br /&gt;                         &lt;br /&gt;                         &lt;strong&gt;&lt;a name="#RecurCTE"&gt;&lt;/a&gt;Recursive CTE methods &lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         The idea behind this method is from a newsgroup posting by Vadim Tropashko similar to the ideas behind generating a materialized path                         for hierarchies.                          WITH CTE ( CategoryId, product_list, product_name, length )&lt;br/&gt;                         AS ( SELECT CategoryId, CAST( '' AS VARCHAR(8000) ), CAST( '' AS VARCHAR(8000) ), 0&lt;br/&gt;                         FROM Northwind..Products&lt;br/&gt;                         GROUP BY CategoryId&lt;br/&gt;                         UNION ALL&lt;br/&gt;                         SELECT p.CategoryId, CAST( product_list +&lt;br/&gt;                         CASE WHEN length = 0 THEN '' ELSE ', ' END + ProductName AS VARCHAR(8000) ),&lt;br/&gt;                         CAST( ProductName AS VARCHAR(8000)), length + 1&lt;br/&gt;                         FROM CTE c&lt;br/&gt;                         INNER JOIN Northwind..Products p&lt;br/&gt;                         ON c.CategoryId = p.CategoryId&lt;br/&gt;                         WHERE p.ProductName &amp;gt; c.product_name )&lt;br/&gt;                         SELECT CategoryId, product_list&lt;br/&gt;                         FROM ( SELECT CategoryId, product_list,&lt;br/&gt;                         RANK() OVER ( PARTITION BY CategoryId ORDER BY length DESC )&lt;br/&gt;                         FROM CTE ) D ( CategoryId, product_list, rank )&lt;br/&gt;                         WHERE rank = 1 ;&lt;br/&gt;                                                  The CASE in the recursive part of the CTE is used to eliminate the initial comma and you can use RIGHT or the SUBSTRING functions                         to substitute it. Also, this may not be the best performing option, however certain additional tuning could be done to make them                         suitable for medium sized datasets.                         &lt;br /&gt;                         &lt;br /&gt;                         Another approach using recursive common table expressions was sent in by Anub Philip, an Engineer from Sathyam Computers that uses                         separate common table expressions for the anchor and recursive parts.                          WITH Ranked ( CategoryId, rnk, ProductName )&lt;br/&gt;                         AS ( SELECT CategoryId,&lt;br/&gt;                         ROW_NUMBER() OVER( PARTITION BY CategoryId ORDER BY CategoryId ),&lt;br/&gt;                         CAST( ProductName AS VARCHAR(8000) )&lt;br/&gt;                         FROM Northwind..Products),&lt;br/&gt;                         AnchorRanked ( CategoryId, rnk, ProductName )&lt;br/&gt;                         AS ( SELECT CategoryId, rnk, ProductName&lt;br/&gt;                         FROM Ranked&lt;br/&gt;                         WHERE rnk = 1 ),&lt;br/&gt;                         RecurRanked ( CategoryId, rnk, ProductName )&lt;br/&gt;                         AS ( SELECT CategoryId, rnk, ProductName&lt;br/&gt;                         FROM AnchorRanked&lt;br/&gt;                         UNION ALL&lt;br/&gt;                         SELECT Ranked.CategoryId, Ranked.rnk,&lt;br/&gt;                         RecurRanked.ProductName + ', ' + Ranked.ProductName&lt;br/&gt;                         FROM Ranked&lt;br/&gt;                         INNER JOIN RecurRanked&lt;br/&gt;                         ON Ranked.CategoryId = RecurRanked.CategoryId&lt;br/&gt;                         AND Ranked.rnk = RecurRanked.rnk + 1 )&lt;br/&gt;                         SELECT CategoryId, MAX( ProductName )&lt;br/&gt;                         FROM RecurRanked&lt;br/&gt;                         GROUP BY CategoryId;&lt;br/&gt;                                                  On an initial glance, this query may seem a bit expensive in comparison, however the reader is encouraged check the execution plans and                         make any additional tweaks as needed.                         &lt;br /&gt;                         &lt;br /&gt;                         &lt;strong&gt;&lt;a name="#BBXML"&gt;&lt;/a&gt;The blackbox XML methods&lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         An example for string concatenation using FOR XML clause with PATH mode is detailed below. It was initially posted by Eugene Kogan                         later became common in public newsgroups.                          SELECT p1.CategoryId,&lt;br/&gt;                         ( SELECT ProductName + ','&lt;br/&gt;                         FROM Northwind.dbo.Products p2&lt;br/&gt;                         WHERE p2.CategoryId = p1.CategoryId&lt;br/&gt;                         ORDER BY ProductName&lt;br/&gt;                         FOR XML PATH('') ) AS Products&lt;br/&gt;                         FROM Northwind.dbo.Products p1&lt;br/&gt;                         GROUP BY CategoryId ;&lt;br/&gt;                                                  Again, the similar approach originally found in the beta newsgroups, using CROSS APPLY operator.                          SELECT DISTINCT CategoryId, ProductNames&lt;br/&gt;                         FROM Products p1&lt;br/&gt;                         CROSS APPLY ( SELECT ProductName + ','&lt;br/&gt;                         FROM Products p2&lt;br/&gt;                         WHERE p2.CategoryId = p1.CategoryId&lt;br/&gt;                         ORDER BY ProductName&lt;br/&gt;                         FOR XML PATH('') ) D ( ProductNames )&lt;br/&gt;                                                  You may notice a comma at the end of the concatenated string, which you can remove using a STUFF, SUBSTRING or LEFT function. While the                         above methods are deemed reliable by many at the time of writing, there is no guarantee that it will stay that way given the internal                         workings and evaluation rules of FOR XML PATH() expression in correlated subqueries are not well documented.                         &lt;br /&gt;                         &lt;br /&gt;                         &lt;strong&gt;&lt;a name="#UsingCLR"&gt;&lt;/a&gt;Using Common Language Runtime&lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         Though this article is about approaches using Transact SQL, this section is included due to the popularity of CLR aggregates in SQL 2005. Not only it                         empowers the CLR programmer with new options for database development, in some cases, they work at least as well as native Transact                         SQL approaches.                         &lt;br /&gt;                         &lt;br /&gt;                         If you are familiar with .NET languages, SQL 2005 offers a convenient way to create user defined aggregate functions using C#, VB.NET or                         similar languages that is supported by the Common Language Runtime (CLR). Here is an example of a string concatenate aggregate function                         written using C#.                         &lt;br /&gt;                         &lt;br /&gt;                          using System;&lt;br/&gt;                         using System.Collections.Generic;&lt;br/&gt;                         using System.Data.SqlTypes;&lt;br/&gt;                         using System.IO;&lt;br/&gt;                         using Microsoft.SqlServer.Server;&lt;br/&gt;                         [Serializable]&lt;br/&gt;                         [SqlUserDefinedAggregate(Format.UserDefined, MaxByteSize=8000)]&lt;br/&gt;                         public struct strconcat : IBinarySerialize{&lt;br/&gt;                         private List&lt;string&gt; values;&lt;br/&gt;                         public void Init() {&lt;br/&gt;                         this.values = new List&lt;string&gt;();&lt;br/&gt;                         }&lt;br/&gt;                         public void Accumulate(SqlString value) {&lt;br/&gt;                         this.values.Add(value.Value);&lt;br/&gt;                         }&lt;br/&gt;                         public void Merge(strconcat value) {&lt;br/&gt;                         this.values.AddRange(value.values.ToArray());&lt;br/&gt;                         }&lt;br/&gt;                         public SqlString Terminate() {&lt;br/&gt;                         return new SqlString(string.Join(", ", this.values.ToArray()));&lt;br/&gt;                         }&lt;br/&gt;                         public void Read(BinaryReader r) {&lt;br/&gt;                         int itemCount = r.ReadInt32();&lt;br/&gt;                         this.values = new List&lt;string&gt;(itemCount);&lt;br/&gt;                         for (int i = 0; i &amp;lt;= itemCount - 1; i++) {&lt;br/&gt;                         this.values.Add(r.ReadString());&lt;br/&gt;                         }&lt;br/&gt;                         }&lt;br/&gt;                         public void Write(BinaryWriter w) {&lt;br/&gt;                         w.Write(this.values.Count);&lt;br/&gt;                         foreach (string s in this.values) {&lt;br/&gt;                         w.Write(s);&lt;br/&gt;                         }&lt;br/&gt;                         }&lt;br/&gt;                         }&lt;br/&gt;                         &lt;/string&gt;&lt;/string&gt;&lt;/string&gt;                         Once you build and deploy this assembly on the server, you should be able to execute your concatenation query as:                         &lt;br /&gt;                         &lt;br /&gt;                          SELECT CategoryId,&lt;br/&gt;                         dbo.strconcat(ProductName)&lt;br/&gt;                         FROM Products&lt;br/&gt;                         GROUP BY CategoryId ;&lt;br/&gt;                                                  If you are a total newbie on CLR languages, and would like to learn more about developing database solutions using CLR languages,                         consider starting at &lt;a href="http://msdn2.microsoft.com/en-us/library/ms131089.aspx"&gt;Introduction to Common Language Runtime (CLR)                         Integration&lt;/a&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         &lt;strong&gt;&lt;a name="#ScalarRecur"&gt;&lt;/a&gt;Scalar UDF with recursion &lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         Recursive functions in t-SQL have a drawback that the maximum nesting level is 32. So this approach is applicable only for smaller                         datasets, especially when the number of items within a group, that needs to be concatenated, is less than 32.                          CREATE FUNCTION udf_recursive ( @cid INT, @i INT )&lt;br/&gt;                         RETURNS VARCHAR(8000) AS BEGIN&lt;br/&gt;                         DECLARE @r VARCHAR(8000), @l VARCHAR(8000)&lt;br/&gt;                         SELECT @i = @i - 1, @r = ProductName + ', '&lt;br/&gt;                         FROM Products p1&lt;br/&gt;                         WHERE CategoryId = @cid&lt;br/&gt;                         AND @i = ( SELECT COUNT(*) FROM Products p2&lt;br/&gt;                         WHERE p2.CategoryId = p1.CategoryId&lt;br/&gt;                         AND p2.ProductName &amp;lt;= p1.ProductName ) ;&lt;br/&gt;                         IF @i &amp;gt; 0 BEGIN&lt;br/&gt;                         EXEC @l = dbo.udf_recursive @cid, @i ;&lt;br/&gt;                         SET @r = @l + @r ;&lt;br/&gt;                         END&lt;br/&gt;                         RETURN @r ;&lt;br/&gt;                         END&lt;br/&gt;                                                  This function can be invoked as follows:                          SELECT CategoryId,&lt;br/&gt;                         dbo.udf_recursive( CategoryId, COUNT(ProductName) )&lt;br/&gt;                         FROM Products&lt;br/&gt;                         GROUP BY CategoryId ;&lt;br/&gt;                                                  &lt;strong&gt;&lt;a name="#TblUDF"&gt;&lt;/a&gt;Table valued UDF with a WHILE loop &lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         This approach is based on the idea by Linda Wierzbecki where a table variable with three columns is used within a table valued UDF.                         The first column represents the group, second represents the currently processing value within a group and the third represents the                         concatenated list of values.                          CREATE FUNCTION udf_tbl_Concat() RETURNS @t TABLE(&lt;br/&gt;                         CategoryId INT,&lt;br/&gt;                         Product VARCHAR(40),&lt;br/&gt;                         list VARCHAR(8000) )&lt;br/&gt;                         BEGIN&lt;br/&gt;                         INSERT @t (CategoryId, Product, list)&lt;br/&gt;                         SELECT CategoryId, MIN(ProductName), MIN(ProductName)&lt;br/&gt;                         FROM Products&lt;br/&gt;                         GROUP BY CategoryId&lt;br/&gt;                         WHILE ( SELECT COUNT(Product) FROM @t ) &amp;gt; 0 BEGIN&lt;br/&gt;                         UPDATE t&lt;br/&gt;                         SET list = list + COALESCE(&lt;br/&gt;                         ( SELECT ', ' + MIN( ProductName )&lt;br/&gt;                         FROM Products&lt;br/&gt;                         WHERE Products.CategoryId = t.CategoryId&lt;br/&gt;                         AND Products.ProductName &amp;gt; t.Product), ''),&lt;br/&gt;                         Product = ( SELECT MIN(ProductName)&lt;br/&gt;                         FROM Products&lt;br/&gt;                         WHERE Products.CategoryId = t.CategoryId&lt;br/&gt;                         AND Products.ProductName &amp;gt; t.Product )&lt;br/&gt;                         FROM @t t END&lt;br/&gt;                         RETURN&lt;br/&gt;                         END&lt;br/&gt;                                                  The usage of the above function can be like:                          SELECT CategoryId, list AS Products&lt;br/&gt;                         FROM udf_tbl_Concat() ;&lt;br/&gt;                                                  &lt;strong&gt;&lt;a name="#DynamicSQL"&gt;&lt;/a&gt;Dynamic SQL&lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         This approach is a variation of the kludge often known using the nickname as dynamic cross tabulation.                         &lt;br /&gt;                         &lt;br /&gt;                         This approach is a variation of the kludge often known using the nickname as dynamic cross tabulation. There is enough literature out                         there which demonstrates the drawbacks and implications of using Dynamic SQL. A popular one, at least from Transact SQL programmer&amp;#8217;s                         perspective, is Erland's &lt;a href="http://www.sommarskog.se/dynamic_sql.html"&gt;Curse and Blessings of Dynamic SQL.&lt;/a&gt; The Dynamic SQL                         approaches can be developed based on creating a Transact SQL query string based on the number of groups and then use a series of CASE                         expressions or ROW_NUMBER() function to pivot the data for concatenation.                          DECLARE @r VARCHAR(MAX), @n INT, @i INT&lt;br/&gt;                         SELECT @i = 1,&lt;br/&gt;                         @r = 'SELECT CategoryId, ' + CHAR(13),&lt;br/&gt;                         @n = (SELECT TOP 1 COUNT( ProductName )&lt;br/&gt;                         FROM Products&lt;br/&gt;                         GROUP BY CategoryId&lt;br/&gt;                         ORDER BY COUNT( ProductName ) DESC ) ;&lt;br/&gt;                         WHILE @i &amp;lt;= @n BEGIN&lt;br/&gt;                         SET @r = @r +&lt;br/&gt;                         CASE WHEN @i = 1&lt;br/&gt;                         THEN 'MAX( CASE Seq WHEN ' + CAST( @i AS VARCHAR ) + '&lt;br/&gt;                         THEN ProductName&lt;br/&gt;                         ELSE SPACE(0) END ) + ' + CHAR(13)&lt;br/&gt;                         WHEN @i = @n&lt;br/&gt;                         THEN 'MAX( CASE Seq WHEN ' + CAST( @i AS VARCHAR ) + '&lt;br/&gt;                         THEN '', '' + ProductName&lt;br/&gt;                         ELSE SPACE(0) END ) ' + CHAR(13)&lt;br/&gt;                         ELSE 'MAX( CASE Seq WHEN ' + CAST( @i AS VARCHAR ) + '&lt;br/&gt;                         THEN '', '' + ProductName&lt;br/&gt;                         ELSE SPACE(0) END ) + ' + CHAR(13)&lt;br/&gt;                         END ;&lt;br/&gt;                         SET @i = @i + 1 ;&lt;br/&gt;                         END&lt;br/&gt;                         SET @r = @r + '&lt;br/&gt;                         FROM ( SELECT CategoryId, ProductName,&lt;br/&gt;                         ROW_NUMBER() OVER ( PARTITION BY CategoryId ORDER BY ProductName )&lt;br/&gt;                         FROM Products p ) D ( CategoryId, ProductName, Seq )&lt;br/&gt;                         GROUP BY CategoryId;'&lt;br/&gt;                         EXEC( @r ) ;&lt;br/&gt;                                                  &lt;strong&gt;&lt;a name="#Cursor"&gt;&lt;/a&gt;The Cursor approach&lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         The drawbacks of rampant usage of cursors are well-known among the Transact SQL community. Given the fact that they are generally                         resource intensive, procedural and inefficient, one should strive to avoid cursors or loop based solutions in general Transact SQL                         programming.                          DECLARE @tbl TABLE (id INT PRIMARY KEY, list VARCHAR(8000))&lt;br/&gt;                         SET NOCOUNT ON&lt;br/&gt;                         DECLARE @c INT, @p VARCHAR(8000), @cNext INT, @pNext VARCHAR(40)&lt;br/&gt;                         DECLARE c CURSOR FOR&lt;br/&gt;                         SELECT CategoryId, ProductName&lt;br/&gt;                         FROM Products&lt;br/&gt;                         ORDER BY CategoryId, ProductName ;&lt;br/&gt;                         OPEN c ;&lt;br/&gt;                         FETCH NEXT FROM c INTO @cNext, @pNext ;&lt;br/&gt;                         SET @c = @cNext ;&lt;br/&gt;                         WHILE @@FETCH_STATUS = 0 BEGIN&lt;br/&gt;                         IF @cNext &amp;gt; @c BEGIN&lt;br/&gt;                         INSERT @tbl SELECT @c, @p ;&lt;br/&gt;                         SELECT @p = @PNext, @c = @cNext ;&lt;br/&gt;                         END ELSE&lt;br/&gt;                         SET @p = COALESCE(@p + ',', SPACE(0)) + @pNext ;&lt;br/&gt;                         FETCH NEXT FROM c INTO @cNext, @pNext&lt;br/&gt;                         END&lt;br/&gt;                         INSERT @tbl SELECT @c, @p ;&lt;br/&gt;                         CLOSE c ;&lt;br/&gt;                         DEALLOCATE c ;&lt;br/&gt;                         SELECT * FROM @tbl ;&lt;br/&gt;                                                  &lt;strong&gt;&lt;a name="#Unreliable"&gt;&lt;/a&gt;Non-reliable approaches&lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         This section details a couple of notorious methods often publicized by some in public forums. The problem with these methods is that                         they rely on the physical implementation model; changes in indexes, statistics etc or even a change of a simple expression in the                         SELECT list or ORDER BY clause can change the output. Also these are undocumented, unsupported and unreliable to the point where one                         can consistently demonstrate failures. Therefore these methods are not at all recommended for production mode systems.                         &lt;br /&gt;                         &lt;br /&gt;                         &lt;strong&gt;&lt;a name="#UpdateExtn"&gt;&lt;/a&gt;Scalar UDF with t-SQL update extension &lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         The usage of an expression that involves a column, a variable and an expression in the SET clause in an UPDATE statement rarely appear                         intuitive. However, in general, the optimizer often seems to process these values in the order of materialization, either in the internal                         work tables or any other storage structures.                          CREATE FUNCTION udf_update_concat (@CategoryId INT)&lt;br/&gt;                         RETURNS VARCHAR(MAX) AS&lt;br/&gt;                         BEGIN&lt;br/&gt;                         DECLARE @t TABLE(p VARCHAR(40));&lt;br/&gt;                         DECLARE @r VARCHAR(MAX) ;&lt;br/&gt;                         SET @r = SPACE(0) ;&lt;br/&gt;                         INSERT @t ( p ) SELECT ProductName FROM Products&lt;br/&gt;                         WHERE CategoryId = @CategoryId ;&lt;br/&gt;                         IF @@ROWCOUNT &amp;gt; 0&lt;br/&gt;                         UPDATE @t&lt;br/&gt;                         SET @r = @r + p + ',' ;&lt;br/&gt;                         RETURN(@r)&lt;br/&gt;                         END&lt;br/&gt;                                                  Here is how to use this function:                          SELECT CategoryId, dbo.udf_update_concat(CategoryId)&lt;br/&gt;                         FROM Products&lt;br/&gt;                         GROUP BY CategoryId ;&lt;br/&gt;                                                  Again, it is important to consider that lack of physical independence that is being exploited here before using or recommending this as                         a usable and meaningful solution.                         &lt;br /&gt;                         &lt;br /&gt;                         &lt;strong&gt;&lt;a name="#SelectConcat"&gt;&lt;/a&gt;Scalar UDF with variable concatenation in SELECT &lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         This is an approachpurely dependent on the physical implementation and internal access paths. Before using this approach, make sure to                         refer to the &lt;a href="http://support.microsoft.com/default.aspx/kb/287515"&gt;relevant knowledgebase article&lt;/a&gt;.                          CREATE FUNCTION dbo.udf_select_concat ( @c INT )&lt;br/&gt;                         RETURNS VARCHAR(MAX) AS BEGIN&lt;br/&gt;                         DECLARE @p VARCHAR(MAX) ;&lt;br/&gt;                         SET @p = '' ;&lt;br/&gt;                         SELECT @p = @p + ProductName + ','&lt;br/&gt;                         FROM Products&lt;br/&gt;                         WHERE CategoryId = @c ;&lt;br/&gt;                         RETURN @p&lt;br/&gt;                         END&lt;br/&gt;                                                  And, as for its usage:                          SELECT CategoryId, dbo.udf_select_concat( CategoryId )&lt;br/&gt;                         FROM Products&lt;br/&gt;                         GROUP BY CategoryId ;&lt;br/&gt;                                                  &lt;strong&gt;&lt;a name="#Concl"&gt;&lt;/a&gt;Conclusion&lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         Regardless of how it is used, "aggregate concatenation" of row values in Transact SQL, especially when there is a grouping, is not                         a simple routine. Various programming considerations are to be carefully considered to choose one method over another depending on                         the situations. The most logical choice would be the availability of a built-in operator with optional configurable parameters that                         can do the concatenation of the values depending on the type. Till then, reporting requirements and external data export routines                         will have to rely on such Transact SQL programming hacks.                         &lt;br /&gt;                         &lt;br /&gt;                         &lt;strong&gt;&lt;a name="#Refer"&gt;&lt;/a&gt;References&lt;/strong&gt;                         &lt;ul&gt;                             &lt;li&gt;&lt;a href="http://support.microsoft.com/default.aspx/kb/287515"&gt;PRB: Execution Plan and Results of Aggregate Concatenation                             Queries Depend Upon Expression Location&lt;/a&gt;&lt;/li&gt;                             &lt;li&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=06616212-0356-46a0-8da2-eebc53a68034&amp;amp;displaylang=en"&gt;Northwind and pubs                             Sample Databases for SQL Server 2000&lt;/a&gt;&lt;/li&gt;                             &lt;li&gt;&lt;a href="http://www.sommarskog.se/dynamic_sql.html"&gt;The Curse and Blessings of Dynamic SQL&lt;/a&gt;&lt;/li&gt;                             &lt;li&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/ms131089.aspx"&gt;Introduction to Common Language Runtime (CLR) Integration&lt;/a&gt;&lt;/li&gt;                         &lt;/ul&gt;                         &lt;strong&gt;&lt;a name="#Acknow"&gt;&lt;/a&gt;Acknowledgements&lt;/strong&gt;                         &lt;br /&gt;                         &lt;br /&gt;                         Umachandar Jayachandran, Linda Wierzbecki, Bruce Margolin, Roy Harvey, Eugene Kogan, Vadim Tropashko, Anub Philip.                         &lt;/td&gt;                     &lt;/tr&gt;                 &lt;/tbody&gt;             &lt;/table&gt;             &lt;/td&gt;             &lt;td align="center" style="width: 100px"&gt;&lt;/td&gt;         &lt;/tr&gt;     &lt;/tbody&gt;&lt;/table&gt;&lt;img src="http://www.cnblogs.com/michael-zhang/aggbug/2101031.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/michael-zhang/archive/2011/07/08/2101031.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/michael-zhang/archive/2008/11/24/1339918.html</id><title type="text">silverlight小游戏:　贪吃蛇</title><summary type="text">发布个好玩的小游戏 ;) 有兴趣的在此下载源码.有点小问题:1, silverlight中没有Invoke方法, 用BeginInvoke更新UI时, 设置速度值为30以内刷新会出问题, 不知道有什么解决办法没 ;(2, 附源码中有个winForm版的, 每次是重绘Panel对象的几个小方块内容; 试过缓存bitmap, 重绘整个panel的方式, 好像屏幕更闪了; 不知道专业的小游戏是采取哪种方...</summary><published>2008-11-24T07:51:00Z</published><updated>2008-11-24T07:51:00Z</updated><author><name>lin-zhang</name><uri>http://www.cnblogs.com/michael-zhang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/michael-zhang/archive/2008/11/24/1339918.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/michael-zhang/archive/2008/11/24/1339918.html"/><content type="text">发布个好玩的小游戏 ;) 有兴趣的在此下载源码.有点小问题:1, silverlight中没有Invoke方法, 用BeginInvoke更新UI时, 设置速度值为30以内刷新会出问题, 不知道有什么解决办法没 ;(2, 附源码中有个winForm版的, 每次是重绘Panel对象的几个小方块内容; 试过缓存bitmap, 重绘整个panel的方式, 好像屏幕更闪了; 不知道专业的小游戏是采取哪种方...</content></entry><entry><id>http://www.cnblogs.com/michael-zhang/archive/2007/02/17/651831.html</id><title type="text">SharpPad文本编辑器: 已完成添加代码自动完成、代码折叠等功能</title><summary type="text">SharpDevelop分析系列已写到第四篇 SharpDevelop浅析_4_TextEditor_自动完成、代码折叠…… , 至此已基本补充完整 SharpPad的功能，与第三篇中的 Demo 相比，增加了代码自动完成、代码折叠、类/成员 快速定位等功能访问此处(http://www.cnblogs.com/michael-zhang/articles/651825.html) 以查看详情</summary><published>2007-02-16T17:45:00Z</published><updated>2007-02-16T17:45:00Z</updated><author><name>lin-zhang</name><uri>http://www.cnblogs.com/michael-zhang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/michael-zhang/archive/2007/02/17/651831.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/michael-zhang/archive/2007/02/17/651831.html"/><content type="text">SharpDevelop分析系列已写到第四篇 SharpDevelop浅析_4_TextEditor_自动完成、代码折叠…… , 至此已基本补充完整 SharpPad的功能，与第三篇中的 Demo 相比，增加了代码自动完成、代码折叠、类/成员 快速定位等功能访问此处(http://www.cnblogs.com/michael-zhang/articles/651825.html) 以查看详情</content></entry><entry><id>http://www.cnblogs.com/michael-zhang/archive/2007/02/01/636387.html</id><title type="text">SharpDevelop浅析_3_Internationalization-TextEditor __ 读书心得</title><summary type="text">首先，庆贺下自己的"SharpDevelop浅析_3_Internationalization-TextEditor分析文章"在一周的艰苦努力中终于写了出来在这一周读代码的学习过程中颇有些感受，总结起来有以下几点收获：坚持、自信： 上周末看了电子书的相关章节，然后读代码，周末两天的时间看下来仍是一头雾水，接下来的三天中也仍是有许多困惑，有时会想工作的事不少，下班还要搞这个分析，而且又公开在博客上了还给自己定时间争取年底前完成整个SharpDevelop分析，这不自找麻烦。但是坚持下来写出读书心得时便会庆幸自己坚持了下来。跳过细节、总体把握： 读代码时遇到许多不清楚的，如果想在一周内把每个细节都搞清楚时间上肯定不够，而且现在想想也不符合学习规律，只要在不影响全局理解的情况下，重点要先对整个事情有个全局的把握，然后一步步细化，看感兴趣的具体细节实现。要会提问题： 对事物/项目的了解要在有一定的认识后不断的提出问题、找答案，在这个过程中才会有更深的理解，如果提不出问题，只是一味地读代码，相信到现在我也分析不出个头绪。</summary><published>2007-01-31T19:43:00Z</published><updated>2007-01-31T19:43:00Z</updated><author><name>lin-zhang</name><uri>http://www.cnblogs.com/michael-zhang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/michael-zhang/archive/2007/02/01/636387.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/michael-zhang/archive/2007/02/01/636387.html"/><content type="text">首先，庆贺下自己的"SharpDevelop浅析_3_Internationalization-TextEditor分析文章"在一周的艰苦努力中终于写了出来在这一周读代码的学习过程中颇有些感受，总结起来有以下几点收获：坚持、自信： 上周末看了电子书的相关章节，然后读代码，周末两天的时间看下来仍是一头雾水，接下来的三天中也仍是有许多困惑，有时会想工作的事不少，下班还要搞这个分析，而且又公开在博客上了还给自己定时间争取年底前完成整个SharpDevelop分析，这不自找麻烦。但是坚持下来写出读书心得时便会庆幸自己坚持了下来。跳过细节、总体把握： 读代码时遇到许多不清楚的，如果想在一周内把每个细节都搞清楚时间上肯定不够，而且现在想想也不符合学习规律，只要在不影响全局理解的情况下，重点要先对整个事情有个全局的把握，然后一步步细化，看感兴趣的具体细节实现。要会提问题： 对事物/项目的了解要在有一定的认识后不断的提出问题、找答案，在这个过程中才会有更深的理解，如果提不出问题，只是一味地读代码，相信到现在我也分析不出个头绪。</content></entry><entry><id>http://www.cnblogs.com/michael-zhang/archive/2007/01/25/629739.html</id><title type="text">SharpDevelop代码分析</title><summary type="text">最近在作.NET的C/S项目，由于经验比较少，便想通过读《Dissecting a C# Application Inside SharpDevelop》结合SharpDevelop源码的学习，全面地了解一下好的应用程序是如何编写的，从中不但能锻炼编程能力，也可以进行一些架构的思考。到现在已写了两篇读后感文章，好像没被其他人看到过，便写了这篇随笔放在首页，希望大家园子里的朋友多支持下，多多评论、交流 :-)SharpDevelop分析（http://www.cnblogs.com/michael-zhang/category/82115.html）SharpDevelop浅析_序 （http://www.cnblogs.com/michael-zhang/articles/621144.html）</summary><published>2007-01-24T16:19:00Z</published><updated>2007-01-24T16:19:00Z</updated><author><name>lin-zhang</name><uri>http://www.cnblogs.com/michael-zhang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/michael-zhang/archive/2007/01/25/629739.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/michael-zhang/archive/2007/01/25/629739.html"/><content type="text">最近在作.NET的C/S项目，由于经验比较少，便想通过读《Dissecting a C# Application Inside SharpDevelop》结合SharpDevelop源码的学习，全面地了解一下好的应用程序是如何编写的，从中不但能锻炼编程能力，也可以进行一些架构的思考。到现在已写了两篇读后感文章，好像没被其他人看到过，便写了这篇随笔放在首页，希望大家园子里的朋友多支持下，多多评论、交流 :-)SharpDevelop分析（http://www.cnblogs.com/michael-zhang/category/82115.html）SharpDevelop浅析_序 （http://www.cnblogs.com/michael-zhang/articles/621144.html）</content></entry><entry><id>http://www.cnblogs.com/michael-zhang/archive/2007/01/15/621201.html</id><title type="text">博客开张了</title><summary type="text">工作中的项目感觉锻炼不大，业余随便看点什么又总是水过无痕，于是写博客吧。在沦浪之水的QQ群(26227899)中看到公告提醒大家写年度计划，长远的我也计划不了，暂定近一两个月读《Dissecting a C# Application Inside SharpDevelop》写读后感吧，没写过博客，刚花了几个小时发贴子，满头大汗终于把文章发出去了，效果也不是很满意，慢慢来吧。 欢迎园子里的朋友多评论、多交流 :-) </summary><published>2007-01-15T15:28:00Z</published><updated>2007-01-15T15:28:00Z</updated><author><name>lin-zhang</name><uri>http://www.cnblogs.com/michael-zhang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/michael-zhang/archive/2007/01/15/621201.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/michael-zhang/archive/2007/01/15/621201.html"/><content type="text">工作中的项目感觉锻炼不大，业余随便看点什么又总是水过无痕，于是写博客吧。在沦浪之水的QQ群(26227899)中看到公告提醒大家写年度计划，长远的我也计划不了，暂定近一两个月读《Dissecting a C# Application Inside SharpDevelop》写读后感吧，没写过博客，刚花了几个小时发贴子，满头大汗终于把文章发出去了，效果也不是很满意，慢慢来吧。 欢迎园子里的朋友多评论、多交流 :-) </content></entry></feed>
