前言
最近由於公司oracle主機更新
DBA盯長運算的sql盯得特別緊
於是幾個sql server上的古蹟就被挖出來了
也發現了幾個有趣的現象跟大家分享一下
最開始收到DBA傳來的sql是長這樣的
(雖然我覺得table schema算不上機密,但還是改編了一下)
select * from tableA where FLAG<>'Y' and NAME<> 'xxx'
這個tableA裡面包含了日期欄位
每天都有資料進帳,也就是說他是一個不算小的龐大table
看到這句sql不由得驚呼「怎麼會這樣子寫SQL!?」
追查了一下sql server上面的寫法後發現
在sql server上是這麼寫的
insert temptable
SELECT * FROM OPENQUERY(oracle_con, 'select * from tableA') AS a
WHERE FLAG <> 'Y' AND NAME <> 'xxx' AND ID IS NOT NULL
and SDATE>@sdate
這樣的一句指令
在我本來的認知中他去了oracle應該就只有select * from tableA這段而已
有趣的他卻帶了兩個where條件過去,這有點顛覆了我對openquery的認知
不過更有趣的是,最後一個條件是帶參數過去不不意外
但為什麼ID IS NOT NULL這條件也過不去呢?
恩,雖然有趣但這神秘的規則就待以後再慢慢研究了
今天主要想提的是openquery的寫法
正確來說openquery該執行的應該是
select * from tableA' WHERE FLAG <> 'Y' AND NAME <> 'xxx' AND ID IS NOT NULL
and SDATE>@sdate
這樣的完整句子才能避免不必要的資源浪費並縮短執行時間
我們來改造一下這段
首先是openquery帶參數的部分
第一段
先來組sql字串吧
DECLARE @TSQL nvarchar(4000)
SELECT @TSQL = 'SELECT * FROM OPENQUERY(oracle_con, ''select * from tableA WHERE FLAG <> ''''Y'''' AND NAME <> ''''xxx'''' AND ID IS NOT NULL
and SDATE>'''''+@sdate+''''' '') AS a '
接著執行
EXEC sp_executesql @TSQL
就有資料了~~~
咦?不對,我們是要insert到temptable裡我要怎麼把executesql裡面的東西拿出來呢!?
傻瓜,包進去就對了
DECLARE @TSQL nvarchar(4000)
SELECT @TSQL = ' insert temptable
SELECT *
FROM OPENQUERY(oracle_con, ''select * from tableA WHERE FLAG <>
''''Y'''' AND NAME <> ''''xxx'''' AND ID IS NOT NULL
and SDATE>'+@sdate+' '') AS a'
EXEC sp_executesql @TSQL
稍微說一下因為在nvarchar裡,一個'要變兩個'
然後openquery裡面的因為是字串裡的字串,所以兩個'要再變成四個'
總之就是很多個點
這裡隱藏了一個亮點
「為什麼你的SDATE沒有點!!!不對他是oracle的話你就算點了也沒用」
恩......不瞞您說.....SDATE這欄位.....是個NUMBER.......
如果真的要帶日期的參數.....Convert這麼好用自己轉一轉再用字串去帶吧!!
2015年12月22日 星期二
2015年4月21日 星期二
[C#]老師,外部執行檔不理我
這篇文章的出現是有歷史共業在的
隨著時光飛逝科技進步
一間公司經營久了系統多了人也老了
便開始出現了所謂的"舊系統"跟"新系統"
舊系統只要還堪用也舉不出什麼致命的缺陷
在人力資源不足的狀況下往往就會讓他繼續活下去
而新系統開發時在資源再利用的思維模式作祟下
就會有引用舊系統功能的需求出現
"寫成一個service大家用阿"
傻瓜,連dll都拿不到了還指望service
最後各退一步就是呼叫你的執行檔給你參數你output資料給我
賀,前言說了這麼多開始進入正題
協調好資料交換的格式之後,得到了一個精美的exe執行檔
裡面做什麼事你完全不知道,他會給你什麼結果你也無法預期
會跳error已經是很好的狀況了
最糟的是他什麼都不給你就一直hang住
同理心,執行檔會hang住肯定是出現了什麼他也沒預料到的特殊狀況才這樣
天助自助者,我們自己給的timeout設定不就得了
一般來說C#呼叫執行檔取output你會這麼寫
string ret = string.Empty;
using (Process proc = new Process())
{
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.RedirectStandardOutput = true;
//塞入你的參數
proc.StartInfo.Arguments = parameter;
//你的執行檔
proc.StartInfo.FileName = exeFile;
proc.Start();
ret = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
}
在各種無法預期的不可抗力下
你很有機會在ReadToEnd()那邊等上一輩子
設定timeout的寫法
string ret = string.Empty;
using (Process proc = new Process())
{
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.Arguments = parameter;
proc.StartInfo.FileName = exeFile;
StringBuilder output = new StringBuilder();
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
{
proc.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
output.AppendLine(e.Data);
}
};
proc.Start();
proc.BeginOutputReadLine();
//人生苦短不該花費在等待上,設定一個timeout的秒數吧
int waitTimeSecond = 20;
if (proc.WaitForExit(waitTimeSecond * 1000) &&
outputWaitHandle.WaitOne(waitTimeSecond * 1000)
{
ret = output.ToString();
}
// Timed out.
else
{
ret = "老師,外部執行檔不理我";
}
}
}
隨著時光飛逝科技進步
一間公司經營久了系統多了人也老了
便開始出現了所謂的"舊系統"跟"新系統"
舊系統只要還堪用也舉不出什麼致命的缺陷
在人力資源不足的狀況下往往就會讓他繼續活下去
而新系統開發時在資源再利用的思維模式作祟下
就會有引用舊系統功能的需求出現
"寫成一個service大家用阿"
傻瓜,連dll都拿不到了還指望service
最後各退一步就是呼叫你的執行檔給你參數你output資料給我
賀,前言說了這麼多開始進入正題
協調好資料交換的格式之後,得到了一個精美的exe執行檔
裡面做什麼事你完全不知道,他會給你什麼結果你也無法預期
會跳error已經是很好的狀況了
最糟的是他什麼都不給你就一直hang住
同理心,執行檔會hang住肯定是出現了什麼他也沒預料到的特殊狀況才這樣
天助自助者,我們自己給的timeout設定不就得了
一般來說C#呼叫執行檔取output你會這麼寫
string ret = string.Empty;
using (Process proc = new Process())
{
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.RedirectStandardOutput = true;
//塞入你的參數
proc.StartInfo.Arguments = parameter;
//你的執行檔
proc.StartInfo.FileName = exeFile;
proc.Start();
ret = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
}
在各種無法預期的不可抗力下
你很有機會在ReadToEnd()那邊等上一輩子
設定timeout的寫法
string ret = string.Empty;
using (Process proc = new Process())
{
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.Arguments = parameter;
proc.StartInfo.FileName = exeFile;
StringBuilder output = new StringBuilder();
using (AutoResetEvent outputWaitHandle = new AutoResetEvent(false))
{
proc.OutputDataReceived += (sender, e) =>
{
if (e.Data == null)
{
outputWaitHandle.Set();
}
else
{
output.AppendLine(e.Data);
}
};
proc.Start();
proc.BeginOutputReadLine();
//人生苦短不該花費在等待上,設定一個timeout的秒數吧
int waitTimeSecond = 20;
if (proc.WaitForExit(waitTimeSecond * 1000) &&
outputWaitHandle.WaitOne(waitTimeSecond * 1000)
{
ret = output.ToString();
}
// Timed out.
else
{
ret = "老師,外部執行檔不理我";
}
}
}
訂閱:
文章 (Atom)