2012年5月24日 星期四

透過Bat(*.bat)程式傳遞參數給Windows程式(.Exe)並自動關閉執行Bat檔時的Doc視窗(轉)

start c:\Test.exe %1

@Echo Off
cls
EXIT

說明:
1. %1 為呼叫Bat程式時傳遞Bat程式的第一個參數(%2、%3..%9分別表示第2、第3、…、第9個參數)
2. 使用start去啟動Exe程式,可以不必等Exe程式執行結束,Bat的Dos視窗就可以關閉
3. @Echo Off 及 cls 指令用來關閉Bat的Dos視窗(經測試發現,不加Exit指令也可以)
4. Windows程式接收命令行參數的方法如下(以C#為例):
    System.Environment.GetCommandLineArgs().GetValue(1).ToString()
    註:GetValue(1)表示接收第1個參數,依次類推可以接收第2、3個參數

P.S.
批處理程式(.Bat)相關知識:
1. 假設父批處理程序接收兩個可替換參數,並希望將它們傳給Sub.bat。可在父批理程序中使用命令:call Sub.bat%1%2
2. 設置變量,並等待使用者輸入:set /p Name = 請輸入使用者名稱(註:/p 讓執行暫停,並提供使用者輸入的機會)
3. 取得變量值:%變量名稱%
4. 輸出變量值:如:echo 您輸入的使用者名稱為:%Name%
5. 執行時不顯示指令程式碼:@echo off
6. 暫停:pause
7. 註解:::
8. 批參數(%n)的替代已被增強。可以使用以下語法:
        %~1        - 刪除引號("),擴充 %1
        %~f1        - 將 %1 擴充到一個完全合格的路徑名
        %~d1        - 僅將 %1 擴充到一個驅動器號
        %~p1        - 僅將 %1 擴充到一個路徑
        %~n1        - 僅將 %1 擴充到一個文件名
        %~x1        - 僅將 %1 擴充到一個文件擴展名
        %~s1        - 擴充的路徑指含有短名
        %~a1        - 將 %1 擴充到文件屬性
        %~t1        - 將 %1 擴充到文件的日期/時間
        %~z1        - 將 %1 擴充到文件的大小
        %~$PATH : 1 - 查找列在 PATH 環境變量的目錄,並將 %1
                      擴充到找到的第一個完全合格的名稱。如果環境
                      變量名未被定義,或者沒有找到文件,此組合鍵會
                      擴充到空字符串

       可以組合修定符來取得多重結果:
        %~dp1      - 只將 %1 擴展到驅動器號和路徑
        %~nx1      - 只將 %1 擴展到文件名和擴展名
        %~dp$PATH:1 - 在列在 PATH 環境變量中的目錄裡查找 %1,
                      並擴展到找到的第一個文件的驅動器號和路徑。
        %~ftza1    - 將 %1 擴展到類似 DIR 的輸出行。

Sample 1:以下的程式碼片段(*.bat)可以取得目前系統時間的年、月、日、時、分等欄位,當在做一些自動化備份時,可以用時間來當檔名或留下 TIMESTAMP 紀錄。

@echo off
cls

:: 取得今天日期的年、月、日三個欄位(透過 date /t 指令取得)
for /f "tokens=1-4 delims=-/ " %%i IN ('date /t') DO (
set year=%%i
set month=%%j
set day=%%k
)

:: 取得當下時間的時、分兩個欄位
for /f "tokens=1-3 delims=:" %%i IN ('time /t') DO (
set hour=%%i
set minute=%%j
)

:: 濾掉 hour 前面可能會出現的空白
for /f "tokens=1 delims= " %%i IN ("%hour%") DO (
set hour=%%i
)

Sample 2:以下的程式碼片段(*.bat)可以取得目前系統時間的年、月、日、時、分等欄位,當在做一些自動化備份時,可以用時間來當檔名或留下 TIMESTAMP 紀錄。

@echo off
@For /f "tokens=1-3 delims=/ " %%a in ('date /t') do (set date=%%a-%%b-%%c)
@For /f "tokens=2-3 delims=: " %%a in ('time /t') do (set time=%%a:%%b)
@echo DayTime : %date% %time%

Sample 3:Batch 檔取得系統的日期、時間欄位

取得今天日期 ( 其中 P0 代表「不滿 10 自動補零」的意思 )

REM 取得今天的年、月、日 (自動補零)
SET TodayYear=%date:~0,4%
SET TodayMonthP0=%date:~5,2%
SET TodayDayP0=%date:~8,2%

REM 取得今天的年、月、日 (純數字)
SET /A TodayMonth=TodayMonthP0+0
SET /A TodayDay=TodayDayP0+0

echo 日期 %TodayYear%/%TodayMonth%/%TodayDay%
echo 日期 %TodayYear%/%TodayMonthP0%/%TodayDayP0%取得上個月的年、月 ( 其中 P0 代表「不滿 10 自動補零」的意思 )

REM 取得上個月的年、月
SET /A LastMonthYear=%TodayYear%+0
SET /A LastMonthMonth=%TodayMonth%-1
SET /A LastMonthMonthP0=%LastMonthMonth%
REM 修正年份與月份的數值
IF %LastMonthMonth% EQU 0 (SET /A LastMonthYear=%thisYear%-1)
IF %LastMonthMonth% EQU 0 (SET LastMonthMonth=12)
IF %LastMonthMonth% LSS 10 (SET LastMonthMonthP0=0%LastMonthMonth%)

echo 日期 %LastMonthYear%/%LastMonthMonth%
echo 日期 %LastMonthYear%/%LastMonthMonthP0%取得當下時間 ( 時、分、秒、豪秒 )

REM 取得時、分、秒 、豪秒
SET Hour=%NowTime:~0,2%
SET Minute=%NowTime:~3,2%
SET Second=%NowTime:~6,2%
SET /A Millisecond=%NowTime:~9,2%*10

echo 時間 %Hour%:%Minute%:%Second%.%Millisecond%上述關於取得「上個月」的年、月的重點就在於 Batch 可以提供基本的數學運算。另外對於 %time% 的精準度只有到「百分之一秒」,為了改以表達「豪秒」表達所以我將取得的數字乘以 10 處理。

如何在批次檔(Batch)中實現 sleep 命令讓任務暫停執行 n 秒
在批次檔(*.bat)中內建並沒有 SLEEP 命令,當你在執行批次任務時若需要暫停執行幾秒鐘,就需要一些小技巧來實現了,以下分享幾個我之前用過的技巧:
1. 利用 PING 指令幫忙停 5 秒
每壹台電腦都有 PING 執行檔,這個最好用啦!
@ping 127.0.0.1 -n 5 -w 1000 > nul


2. 利用 CHOICE 指令
CHOICE 命令在 Windows XP 中找不到,但在 Windows Server 2003 或 Vista 都有內建。
@CHOICE /C YN /N /T 5 /D y > nul


3. 安裝 Windows Server 2003 Resource Kit Tools 即可獲得 sleep.exe 工具
預設安裝路徑在 C:\Program Files\Windows Resource Kits\Tools 目錄下會有個 sleep.exe 執行檔
sleep 5

XCOPY 用法
http://163.32.135.36/%E6%95%99%E6%9D%90/%E7%B3%BB%E7%B5%B1%E5%82%99%E4%BB%BD%E9%82%84%E5%8E%9F%E5%AF%86%E7%AC%88%E5%8A%9F%E7%95%A5/%E7%B3%BB%E7%B5%B1%E5%82%99%E4%BB%BD%E9%82%84%E5%8E%9F%E5%AF%86%E7%AC%88%E5%8A%9F%E7%95%A5xcopy%E7%AF%87.htm

2012年5月21日 星期一

SQL with 用法


以下內容轉自:http://wudataoge.blog.163.com/blog/static/80073886200961652022389/
一.WITH AS的含義
    WITH AS短語,也叫做子查詢部分(subquery factoring),可以讓你做很多事情,定義一個SQL片斷,該SQL片斷會被整個SQL語句所用到。有的時候,是為了讓SQL語句的可讀性更高些,也有可能是在UNION ALL的不同部分,作為提供數據的部分。
特別對於UNION ALL比較有用。因為UNION ALL的每個部分可能相同,但是如果每個部分都去執行一遍的話,則成本太高,所以可以使用WITH AS短語,則只要執行一遍即可。如果WITH AS短語所定義的表名被調用兩次以上,則優化器會自動將WITH AS短語所獲取的數據放入一個TEMP表裡,如果只是被調用一次,則不會。而提示materialize則是強制將WITH AS短語裡的數據放入一個全局臨時表裡。很多查詢通過這種方法都可以提高速度。
二.使用方法
先看下面一個嵌套的查詢語句:
select * from person.StateProvince where CountryRegionCode in
         (select CountryRegionCode from person.CountryRegion where Name like 'C%')
    上面的查詢語句使用了一個子查詢。雖然這條SQL語句並不復雜,但如果嵌套的層次過多,會使SQL語句非常難以閱讀和維護。因此,也可以使用表變量的方式來解決這個問題,SQL語句如下:
declare @t table(CountryRegionCode nvarchar(3))
insert into @t(CountryRegionCode) (select CountryRegionCode from person.CountryRegion where Name like 'C%')
select * from person.StateProvince where CountryRegionCode
                     in (select * from @t)

    雖然上面的SQL語句要比第一種方式更複雜,但卻將子查詢放在了表變量@t中,這樣做將使SQL語句更容易維護,但又會帶來另一個問題,就是性能的損失。由於表變量實際上使用了臨時表,從而增加了額外的I/O開銷,因此,表變量的方式並不太適合數據量大且頻繁查詢的情況。為此,在SQL Server 2005中提供了另外一種解決方案,這就是公用表表達式(CTE),使用CTE,可以使SQL語句的可維護性,同時,CTE要比表變量的效率高得多。
    下面是CTE的語法:
[ WITH <common_table_expr ession> [ ,n ] ] <common_table_expr ession>::=         expr ession_name [ ( column_name [ ,n ] ) ]     AS         ( CTE_query_definition )



    現在使用CTE來解決上面的問題,SQL語句如下:
with
cr as
(
    select CountryRegionCode from person.CountryRegion where Name like 'C%'
)
select * from person.StateProvince where CountryRegionCode in (select * from cr)
    其中cr是一個公用表表達式,該表達式在使用上與表變量類似,只是SQL Server 2005在處理公用表表達式的方式上有所不同。
    在使用CTE時應注意如下幾點:
1. CTE後面必須直接跟使用CTE的SQL語句(如select、insert、update等),否則,CTE將失效。如下面的SQL語句將無法正常使用CTE:

with
cr as
(
    select CountryRegionCode from person.CountryRegion where Name like 'C%'
)
select * from person.CountryRegion --應將這條SQL語句去掉
--使用CTE的SQL語句應緊跟在相關的CTE後面- -
select * from person.StateProvince where CountryRegionCode in (select * from cr)

2. CTE後面也可以跟其他的CTE,但只能使用一個with,多個CTE中間用逗號(,)分隔,如下面的SQL語句所示:
with
cte1 as
(
    select * from table1 where name like 'abc%'
),
cte2 as
(
    select * from table2 where id > 20
),
cte3 as
(
    select * from table3 where price < 100
)
select a.* from cte1 a, cte2 b, cte3 c where a.id = b.id and a.id = c.id
3. 如果CTE的表達式名稱與某個數據表或視圖重名,則緊跟在該CTE後面的SQL語句使用的仍然是CTE,當然,後面的SQL語句使用的就是數據表或視圖了,如下面的SQL語句所示:

-- table1是一個實際存在的表
with
table1 as
(
    select * from persons where age < 30
)
select * from table1 --使用了名為table1的公共表表達式
select * from table1 --使用了名為table1的數據表
4. CTE 可以引用自身,也可以引用在同一WITH 子句中預先定義的CTE。不允許前向引用。
5. 不能在CTE_query_definition 中使用以下子句:
(1)COMPUTE 或COMPUTE BY
(2)ORDER BY(除非指定了TOP 子句)
(3)INTO
(4)帶有查詢提示的OPTION 子句
(5)FOR XML
(6)FOR BROWSE
6. 如果將CTE 用在屬於批處理的一部分的語句中,那麼在它之前的語句必須以分號結尾,如下面的SQL所示:
declare @s nvarchar(3)
set @s = 'C%'
; --必須加分號
with
t_tree as
(
    select CountryRegionCode from person.CountryRegion where Name like @s
)
select * from person.StateProvince where CountryRegionCode in (select * from t_tree)
    CTE除了可以簡化嵌套SQL語句外,還可以進行遞歸調用,關於這一部分的內容將在下一篇文章中介紹。