2012年8月10日 星期五

續:SQL 資料轉行

SQL資料轉行之後
終於有時間上來補充動態轉換的方法了


declare @Items nvarchar(max),  --不重複的Item轉成欄位
 @sql nvarchar(max)  --將要執行的SQL語法

select @Items=ISNULL(@Items,'')+'['+Item+'],' from Table1 group by Item  --取出Table內不重複的Item
set @Items=SUBSTRING(@Items,0,len(@Items)) --去除最後一個逗號

--將原本語法與轉好的欄位合併成一個字串
set @sql ='
select Name,'+@Items+'
from
(
select Name,Item,Score from Table1
) t
PIVOT (max(Score) for Item in ('+@Items+')) as a'

exec sp_executesql @sql  --執行SQL語法


經過上述方法
就可以將動態資料做轉換動作了
但是很不巧的
這幾天被SA打槍
舒服
因為串字串下SQL語法會發生 SQL Injection 危險

SQL Injection可以參考
SQL Injection (資料隱碼)– 駭客的 SQL填空遊戲(上)
SQL Injection (資料隱碼)– 駭客的 SQL填空遊戲(下)

因此又再做了修改

SQL語法:
--取出原本的資訊,依Item給ID,ID為欄位名稱
select Name,DENSE_RANK() over(order by Item)as [rid],
 Item,Score into #tab
from Table1

--利用ID做轉換的動作
select * into #myResult from (select Name,rid,Score from #tab ) t 
PIVOT (max(Score) for rid in ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])) as a;

--刪除轉換後整欄都為NULL的欄位
begin
 declare @i as int,@colnum as int
 set @i=0;
 set @colnum=0;
 select @colnum=MAX(rid) from #tab

 select @i=SUM(case when [1] is null then 0 else 1 end) from #myResult group by [1];
 if @i<1
 begin
  ALTER TABLE  #myResult DROP COLUMN [1] 
 end 
 else
 begin
  update #myResult
  set [1]=0
  where [1] is null
 end 
 set @i=0
 select @i=SUM(case when [2] is null then 0 else 1 end) from #myResult group by [2];
 if @i<1
 begin
  ALTER TABLE  #myResult DROP COLUMN [2] 
 end
 else
 begin
  update #myResult
  set [2]=0
  where [2] is null
 end 
 ....(將欄位延伸到10,太多就不全貼) 
end

--回傳rid對應Item資料
select rid,Item from #tab group by rid,Item order by rid

--回傳轉換後資料
select * from #myResult

drop table #tab
drop table #myResult

CS語法:
 //首先我們要先建好一個DataTable來存放轉換後資料
 DataTable dt = new DataTable();
 dt.Columns.Add("Name");  //先放Name
 while (dr.Read())
 {
  dt.Columns.Add(dr["Item"].ToString());  //將第一組回傳的Table(Item)依序放入
 }
    
 dr.NextResult();  //準備開始接收第二組回傳的Table(轉換後)
                
 while (dr.Read())
 {
  DataRow dRow = dt.NewRow();  //將目前Read的資料放到DataRow
  int CellCount = dr.FieldCount;  //取得Field數
  for (int i = 0; i < CellCount; i++)  //將欄位依序放入
  {
   dRow[i] = dr[i].ToString();
  }
  dt.Rows.Add(dRow);  //將DataRow加入DataTable
 }
 dr.Close();

以上

回sql目錄
回首頁


2012年7月22日 星期日

如何在提示視窗中顯示 asp.net 控制項

今天聽眾表示說他想要在按鈕上讓滑鼠移過去,出現提視小視窗並讓 asp.net 的控制項 gridview 在裡面顯示。

此次用的資料庫為 northwind,如果您的內容不是控制項而是 HTML,您也可以更換內容,以下為程式碼:

<!--把下面代碼加到<head>與</head>之間-->
    <style type="text/css">
    <!--
    body {
        padding-left:50px;
    }
    a.tip {
        color:red;
        text-decoration: underline;
        position:relative;
    }
    a.tip span{
        display:none; 
    }
    a.tip:hover{
        cursor:hand;
    }
    a.tip:hover .popbox{
        display: block;
        position:absolute;
        padding:10px;
        /* width:100px; 
        height:30px; */
        background:#000000;
        left:60px;
        top:30px;
        color:#FFFFFF;
        text-decoration: none;
    }
    -->
    </style>

...
...
...


<a href="http://www.o-asp.com" class="tip">把滑鼠移上來試試!
    <span class="popbox">
    <!-- 顯示內容開始 -->
    
    
    <asp:GridView ID="gv" runat="server" AutoGenerateColumns="False" 
        CellPadding="4" DataKeyNames="EmployeeID" DataSourceID="northwind" 
        ForeColor="#333333" GridLines="None">
            <AlternatingRowStyle BackColor="White" />
            <Columns>
                <asp:BoundField DataField="EmployeeID" HeaderText="EmployeeID" 
                    InsertVisible="False" ReadOnly="True" SortExpression="EmployeeID" />
                <asp:BoundField DataField="LastName" HeaderText="LastName" 
                    SortExpression="LastName" />
                <asp:BoundField DataField="FirstName" HeaderText="FirstName" 
                    SortExpression="FirstName" />
                <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
                <asp:BoundField DataField="Region" HeaderText="Region" 
                    SortExpression="Region" />
            </Columns>
            <EditRowStyle BackColor="#2461BF" />
            <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
            <RowStyle BackColor="#EFF3FB" />
            <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
            <SortedAscendingCellStyle BackColor="#F5F7FB" />
            <SortedAscendingHeaderStyle BackColor="#6D95E1" />
            <SortedDescendingCellStyle BackColor="#E9EBEF" />
            <SortedDescendingHeaderStyle BackColor="#4870BE" />
        </asp:GridView>
        
        <asp:SqlDataSource ID="northwind" runat="server" 
        ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" 
        SelectCommand="SELECT [EmployeeID], [LastName], [FirstName], [City], [Region] FROM [Employees]">
    </asp:SqlDataSource>
    
    
    <!-- 顯示內容結束 -->
    </span>
    </a>

回aspnet目錄
回首頁

2012年7月12日 星期四

執行字串內javascript指令

今天工作上遇到,以下做個分享
問題:
A視窗傳FunName給B視窗,然後B視窗去執行A視窗FunName的Function

A.aspx
window.open(B.aspx?FunName=Test);

B.aspx
opener.[FunName]();

各位發現問題了嗎?
B視窗要怎麼將字串內的文字當成指令/Function執行呢?

解法1:
使用setTimeout去執行(setTimeout用法請自行查)
setTimeout("opener." + FunName+ "();",10);
.
.
.


這樣就可以去執行A視窗的Function
但問題來了
如果接下來動作是在A視窗的Function執行完成後才能繼續做
但因為
setTimeout是非同步執行
那最後資料就會不正確
更可能直接Error給你看
這時候該怎麼辦呢?

解法2:
先將完整指令存成字串,再用Eval()去執行
var strFun = "opener." + FunName+ "();";
Eval(strFun);
.
.
.


這樣就會執行完A的Function再執行下面動作

對此問題而言
以上2種方法都可以達到執行字串內javascript指令的動作
差別在於
setTimeout 同時並行、節省執行時間
Eval 執行延續、錯誤排除方便

以上提供給大家參考

回aspnet目錄
回首頁