2023年1月31日 星期二

Oracle PL/SQL JSON函數出現 ORA-40474: JSON 資料中包含無效的 UTF-8 位元組序列

 當 Oracle DB Big5 ZHT16MSWIN950 使用 Oracle JSON函數 ORA-40474: JSON 資料中包含無效的 UTF-8 位元組序列,處理方式資料編碼轉換完成後再轉回



with qa as (
select 'TableA' as TT,'DataA' as cc,Convert('中文資料A', 'UTF8' , 'ZHT16MSWIN950') CDA,Convert('中文資料A之A', 'UTF8' , 'ZHT16MSWIN950') CDB from dual
union
select 'TableA' as TT,'DataB' as cc,Convert('中文資料B', 'UTF8' , 'ZHT16MSWIN950') CDA,Convert('中文資料B之B', 'UTF8' , 'ZHT16MSWIN950') CDB from dual)
SELECT replace(Convert(
json_object('Table' value r.TT,
'Data' value (
SELECT json_arrayagg(json_object('CC' value cc, 'CDA' value CDA, 'CDB' value CDB)) FROM qa c WHERE c.TT=r.TT) )
, 'ZHT16MSWIN950', 'UTF8'),'^','') CJSON 
FROM  qa r group by r.TT;

產生結果

{"Table":"TableA","Data":[{"CC":"DataA","CDA":"中文資料A","CDB":"中文資料A之A"},{"CC":"DataB","CDA":"中文資料B","CDB":"中文資料B之B"}]}

2022年11月28日 星期一

T-SQL 字串日期有 "上午","下午" 的格式轉換成標轉日期格式

 WITH QQ AS (

    SELECT '2020/11/27 上午 11:58:44' AA

    UNION ALL

    SELECT '2020/11/27 下午 11:58:44' AA)

    SELECT AA 轉換前

    ,CONVERT(DATETIME,CASE WHEN CHARINDEX('上午',AA)>0 THEN REPLACE(AA, ' 上午','')+' AM'   WHEN CHARINDEX('下午',AA)>0 THEN REPLACE(AA, ' 下午','')+' PM'  END,120)   轉換為日期

    FROM QQ 

    轉換前 轉換日期

2020/11/27 上午 11:58:44 2020/11/27 11:58:44.0000  

2020/11/27 下午 11:58:44 2020/11/27 23:58:44.0000  

2021年12月29日 星期三

T-SQL 取第一天與最後一天

   

SELECT 

DATEADD(YEAR, DATEDIFF(YEAR,0,GETDATE())-6,0) N年第一天

,DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0) 年第一天

,DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0) 季第一天

,DATEADD(M, DATEDIFF(M,0,GETDATE())-10,0) 年第2個月第一天

,DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) 月第一天

,DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0) 周第一天

,DATEADD(MILLISECOND, -2, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) + 1, 0)) 月最後一天2359

,EOMONTH ( GETDATE(),0 ) 月最後一天

2021年11月8日 星期一

Oracle 單筆紀錄欄位與欄位取最大GREATEST ,取最小LEASE

 Oracle 使用 GREATEST(值[欄位]1, 值[欄位]2, ... 值[欄位]_n) 可以取得最大值,反之取最小LEASE

2021年7月14日 星期三

Oracle PL SQL 中使用: 與 & 變數

 Oracle PL SQL 中使用: 與 & 變數

with qq as (select 'A' col1,1 col2 from dual

union all select 'A' col1,2 col2 from dual

union all select 'B' col1,1 col2 from dual

union all select 'B' col1,2 col2 from dual

union all select 'C' col1,1 col2 from dual

union all select 'C' col1,2 col2 from dual)

select * from qq  where col1=:col1

單一變數放 字串A 時 select * from qq  where col1=:col1 結果為

COL1,COL2

A,1

A,2

單一變數放數值 2 時 select * from qq  where col2=:col2 結果為

COL1,COL2

A,2

B,2

C,2


當變數字串要在清單'A','B'時 select * from qq where col1 in (&col1) 

COL1,COL2

A,1

A,2

B,1

B,2

當變數數值要在清單1,2時 select * from qq where col2 in (&col2) 
COL1,COL2
A,1
A,2
B,1
B,2
C,1
C,2




2020年8月26日 星期三

Oracle 將資料列合併成一筆(xml_agg 同)

 方法一 SYS_CONNECT_BY_PATH

WITH QA AS

     (SELECT 'Row1' DROW, 'user1' EMP, 100 NUM  FROM DUAL

      UNION ALL

      SELECT 'Row2' DROW, 'user1' EMP, 90 NUM   FROM DUAL

       UNION ALL

      SELECT 'Row3' DROW, 'user1' EMP, 90 NUM   FROM DUAL

      UNION ALL

      SELECT 'Row4' DROW, 'user1' EMP, 80 NUM   FROM DUAL),

      QB AS (SELECT  EMP,NUM, COUNT(*) OVER (PARTITION BY  EMP  ) CNT,  ROW_NUMBER() OVER (PARTITION BY EMP  ORDER BY NUM)  SEQ    FROM QA )

           SELECT  EMP, SUBSTR(SYS_CONNECT_BY_PATH( NUM, ','), 2) COMBINE FROM QB

WHERE SEQ = CNT START WITH SEQ = 1 CONNECT BY PRIOR SEQ + 1 = SEQ AND PRIOR  EMP=EMP;     

方法二 Listagg

WITH QA AS 

     (SELECT 'Row1' DROW, 'user1' EMP, 100 NUM  FROM DUAL 

      UNION ALL 

      SELECT 'Row2' DROW, 'user1' EMP, 90 NUM   FROM DUAL 

       UNION ALL 

      SELECT 'Row3' DROW, 'user1' EMP, 90 NUM   FROM DUAL 

      UNION ALL 

      SELECT 'Row4' DROW, 'user1' EMP, 80 NUM   FROM DUAL) 

 SELECT  EMP,  LISTAGG(NUM, ',') WITHIN GROUP (ORDER BY NUM) AS  COMBINE FROM QA  group by EMP

2020年7月24日 星期五

Oracle group by 取沒有在 group by 的特定欄位列資料


with  test as (
           select '1' code, 'Get code 1'  name, 1 mpd, 600 amt,'AA' pd  from dual
union all  select '2' code, 'drop code 2'  name, 0 mpd, -600 amt,'AA' pd  from dual
union all  select '3' code, 'Gte code 3'  name, 1 mpd, 100 amt,'BB' pd  from dual 
     )
select   pd,sum(amt) as total,
         min(code) keep (dense_rank last order by mpd) as code,
         min(name) keep (dense_rank last order by mpd) as name
from     test group by pd

2020年7月13日 星期一

Oracle TABLE 移動 tablespace

變更連線
ALTER SESSION SET CURRENT_SCHEMA =Owner;
移動資料表,資料移動期間整個 table  lock 
ALTER TABLE   OBJECT_NAME   MOVE TABLESPACE  NEW;
重建Index
ALTER INDEX  INDEX_NAME REBUILD TABLESPACE NEWNDX ;



T-SQL Select 設定null 欄位型態

SELECT   CAST(NULL as VARCHAR2(100)) as  varcchar2,CAST(NULL as date) as  datetime FROM dual;

2014年6月16日 星期一

MS-SQL 欄位值 大小寫識別 T-SQL

最近發現 MS-SQL 字串欄位,大寫 和 小寫 會視為相同的值,資料比對誤判
只要在欄位名稱後 加上 Collate SQL_Latin1_General_CP1_CS_AS 大小就視為不同,
相反 SQL_Latin1_General_CP1_CI_AS 就視為相同

如下案例:
select
case when  'ABC' = 'abc'   then 'Yes' else 'NO' End  NO_CS_AS ,
case when  'ABC' Collate SQL_Latin1_General_CP1_CS_AS
         = 'abc' then 'Yes' else 'NO' End   CS_AS,
case when  'ABC' Collate SQL_Latin1_General_CP1_CI_AS
         = 'abc' then 'Yes' else 'NO' End   CI_AS

select
case when 'Abc'  = 'ABC'   then '字串模糊比對' else 'Abc <> ABC' end AS "資料庫預設",
case when 'Abc' Collate SQL_Latin1_General_CP1_CS_AS = 'ABC' Collate SQL_Latin1_General_CP1_CS_AS  then '字串大小寫比對' else 'Abc <> ABC' end AS "指定大小寫比對",
case when 'Abc' Collate SQL_Latin1_General_CP1_CI_AS = 'ABC' Collate SQL_Latin1_General_CP1_CI_AS  then '字串模糊比對' else 'Abc <> ABC' end as "指定模糊比對"

參考 http://technet.microsoft.com/zh-tw/library/ms180175(v=SQL.105).aspx

2014年2月21日 星期五

mklink 建立資料匣連結

mklink/?
建立符號連結。

MKLINK [[/D] | [/H] | [/J]] Link Target

        /D      建立目錄符號連結。預設是檔案符號連結。
        /H      建立永久連結而不是符號連結。
        /J      建立目錄連接。
        Link    指定新符號連結名稱。
        Target  指定新連結參照的路徑 (相對或絕對)。

2013年1月11日 星期五

MS SQL 使用Rowid 更新資料方法


--Form: http://www.databasejournal.com/features/mssql/article.php/3572301/RowNumber-function-in-SQL-Server-2005.htm

Jan 4, 2006

Row_Number() function in SQL Server 2005

As we all know, SQL Server 2005 has new features when compared to SQL Server 2000. One of the features that we are going to discuss in this article is the Row_Number() function. SQL Server Database administrators and developers have been longing for this function for a long time--now the wait is over.
Traditionally developers and Database administrators used temporary tables and co-related sub-queries to generate calculated row numbers in a query. Now SQL Server 2005 provides a function, which replaces all of the additional resources we used to generate row numbers.
Let us assume that we have the following database [EMPLOYEE TEST] and the following table [EMPLOYEE] in the database. You can use the below query to create the database, table and all the corresponding rows.
USE [MASTER]
GO
IF  EXISTS 
  (SELECT NAME FROM SYS.DATABASES WHERE NAME = N'EMPLOYEE TEST')
DROP DATABASE [EMPLOYEE TEST]
GO
CREATE DATABASE [EMPLOYEE TEST]
GO
USE [EMPLOYEE TEST]
GO
IF  EXISTS 
  (SELECT * FROM SYS.OBJECTS 
  WHERE OBJECT_ID = 
    OBJECT_ID(N'[DBO].[EMPLOYEE]') AND TYPE IN (N'U'))
DROP TABLE [DBO].[EMPLOYEE]
GO
CREATE TABLE EMPLOYEE (EMPID INT, FNAME VARCHAR(50),
LNAME VARCHAR(50))
GO
INSERT INTO EMPLOYEE  (EMPID, FNAME, LNAME) 
VALUES (2021110, 'MICHAEL', 'POLAND')
GO
INSERT INTO EMPLOYEE  (EMPID, FNAME, LNAME) 
VALUES (2021110, 'MICHAEL', 'POLAND')
GO
INSERT INTO EMPLOYEE  (EMPID, FNAME, LNAME) 
VALUES (2021115, 'JIM', 'KENNEDY')
GO
INSERT INTO EMPLOYEE  (EMPID, FNAME, LNAME) 
VALUES (2121000, 'JAMES', 'SMITH')
GO
INSERT INTO EMPLOYEE  (EMPID, FNAME, LNAME) 
VALUES (2011111, 'ADAM', 'ACKERMAN')
GO
INSERT INTO EMPLOYEE  (EMPID, FNAME, LNAME) 
VALUES (3015670, 'MARTHA', 'LEDERER')
GO
INSERT INTO EMPLOYEE  (EMPID, FNAME, LNAME) 
VALUES (1021710, 'MARIAH', 'MANDEZ')
GO
Let us browse the table Employee by using the following SQL Query.
SELECT EMPID, FNAME, LNAME FROM EMPLOYEE
The results of the above query look like illustration 1.0.
2021110MICHAELPOLAND
2021110MICHAELPOLAND
2021115JIMKENNEDY
2121000JAMESSMITH
2011111ADAMACKERMAN
3015670MARTHALEDERER
1021710MARIAHMANDEZ

Illustration 1.0
Traditionally in SQL Server 2000, in order to create row numbers based on the rows available in a table, we used to use the following query.
SELECT ROWID=IDENTITY(int,1,1) , EMPID, FNAME, LNAME 
INTO EMPLOYEE2 FROM EMPLOYEE ORDER BY EMPID
This query created a new table using the identity function in order to generate RowId.
Let us query the table by using the following query.
SELECT RowID, EMPID, FNAME, LNAME FROM EMPLOYEE2
The results of the above query would look like illustration 1.1.
11021710MARIAHMANDEZ
22011111ADAMACKERMAN
32021110MICHAELPOLAND
42021110MICHAELPOLAND
52021115JIMKENNEDY
62121000JAMESSMITH
73015670MARTHALEDERER

Illustration 1.1
In this illustration it is clear that the table has a duplicate row with EMPID = 2021110.
To delete the duplicate row with EMPID = 2021110, we have to delete the row in employee2 table and I cannot delete the duplicate row directly from the Employee table.
SQL Server 2005 provides a new function, Row_Number(), for generating row numbers. In order to delete the duplicate row from the original table we can use the features, Common Table Expression and Row_Number() together.
Let us generate the ROWID using the Row_Number() function based on EMPID.
SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE
The results of the above query would look like illustration 1.2.
11021710MARIAHMANDEZ
22011111ADAMACKERMAN
32021110MICHAELPOLAND
42021110MICHAELPOLAND
52021115JIMKENNEDY
62121000JAMESSMITH
73015670MARTHALEDERER

Illustration 1.2
In this result set, we can identify the duplicate row for the EMPID 2021110.
Let us display the duplicate row using the Common Table expression and Row_Number() function by using the following query.
WITH [EMPLOYEE ORDERED BY ROWID] AS
(SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE)
SELECT * FROM [EMPLOYEE ORDERED BY ROWID] WHERE ROWID =4
The results of the above query would look like illustration 1.3.
42021110MICHAELPOLAND

Illustration 1.3
This duplicate row can be deleted using the Common Table expression and Row_Number() function by using the following query.
WITH [EMPLOYEE ORDERED BY ROWID] AS
(SELECT ROW_NUMBER() OVER (ORDER BY EMPID ASC) AS ROWID, * FROM EMPLOYEE)
DELETE FROM [EMPLOYEE ORDERED BY ROWID] WHERE ROWID =4
Let us query the table using the following query.
SELECT * FROM EMPLOYEE
The results of the above query would look like illustration 1.4.
2021110MICHAELPOLAND
2021115JIMKENNEDY
2121000JAMESSMITH
2011111ADAMACKERMAN
3015670MARTHALEDERER
1021710MARIAHMANDEZ

Illustration 1.4
In this illustration, we can see that the duplicate row has been deleted.

Conclusion

In this article, we have discussed the new features of Row_Number() function and Common Table Expression and used both the features together to delete duplicate rows.
» See All Articles by Columnist MAK

2012年4月6日 星期五

what is difference between wmsys.wm_concat and ListAgg

This thread is to discussion what is difference between wmsys.wm_concat and ListAgg for 11G r2

*************************************************************************
difference1 :-)

wmsys.wm_concat allows distinct option.
ListAgg does not allows it.
create table diffT(sortKey,Val) as
select 1,'aa' from dual union all
select 2,'bb' from dual union all
select 3,'aa' from dual union all
select 4,'dd' from dual;
 
col concatV for a20
 
select wmsys.wm_concat(distinct Val) as concatV from diffT;
 
concatV 
--------
aa,bb,dd


*************************************************************************
difference2 :-)

ListAgg allows to decide string concat order.
wmsys.wm_concat does not allows it.

select ListAgg(Val,',')
       within group(order by sortKey desc) as concatV
from diffT;
 
CONCATV
------------
dd,aa,bb,aa 


*************************************************************************
difference3 :-)

ListAgg allows to decide delimiter.
wmsys.wm_concat does not allows it.

select ListAgg(Val,'***')
       within group(order by sortKey desc) as concatV
from diffT;
 
CONCATV
-----------------
dd***aa***bb***aa


*************************************************************************
difference4 :-)

wmsys.wm_concat allows to be used OLAP function with order by
ListAgg does not allows it.
ListAgg allows only OLAP function without order by.

select sortKey,wmsys.wm_concat(Val)
               over(order by sortKey) as concatV
  from diffT;
 
SORTKEY  CONCATV
-------  -----------
      1  aa
      2  aa,bb
      3  aa,bb,aa
      4  aa,bb,aa,dd


*************************************************************************
difference5 :-)

wmsys.wm_concat allows to be used KEEP
ListAgg does not allows it.

select wmsys.wm_concat(Val) 
       Keep(Dense_Rank First order by Val) as concatV 
  from diffT;
 
CONCATV
-------
aa,aa

wmsys.wm_concat 將資料列轉行

SELECT   code, wmsys.wm_concat (col1) combine
          FROM table
      GROUP BY  code

2011年7月15日 星期五

Ms Sql 重複資料查詢與刪除

--檢查重複排序
WITH Get_Last_cmd
AS
(
  SELECT
    *,GroupID = ROW_NUMBER() OVER (PARTITION BY dbowner,custid,facisno ORDER BY cmopendate desc)
  FROM
    dbo.table
)
Select * FROM Get_Last_cmd order by facisno,cmopendate desc;

 --刪除重復
 WITH Get_Last_cmd
AS
(
  SELECT
    GroupID = ROW_NUMBER() OVER (PARTITION BY dbowner,custid,facisno ORDER BY cmopendate desc)
  FROM
    dbo.table
)
delete * FROM Get_Last_cmd WHERE GroupID > 1;

2010年8月5日 星期四

2010年7月27日 星期二

oracle 日期計算


1日期運算 
2 
31. 更改日期顯示的format 
4 ex. 
5 ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY/MM/DD';    
6 階段作業已被更改    
7           
8 select sysdate from dual;    
9           
10 SYSDATE    
11 ----------    
12 2007/09/20    
13           
14 --只對目前session有效,一個 connect 視為一個 session 
15 
162. 日期 + 數值 
17 ex. 
18 select sysdate + 10 from dual; 
19  
20 SYSDATE+10 
21 ---------- 
22 01-OCT-07  
23        
243. 日期 - 數值 
25 ex. 
26 select sysdate - 10 from dual; 
27 
28 SYSDATE-10 
29 ---------- 
30 11-SEP-07 
31 
324. 日期相減得到日期差 
33 ex. 
34 select sysdate - to_date('20070901','yyyymmdd') aa from dual; 
35  
36           AA 
37 ------------- 
38   20.4508218   
39  
40 --◎ 包含時間,所以有小數 
41 --◎ 可做日期欄位的計算 
42  
43 select trunc(sysdate - to_date('20070901','yyyymmdd')) aa from dual; 
44  
45        AA 
46 ---------- 
47        20 
48 --使用trunc取整數,得到日期 
49 
505. 日期相減得到小時差 
51 ex. 
52 select trunc((sysdate - to_date('20070901','yyyymmdd'))*24) aa from dual; 
53 
54         AA 
55 ---------- 
56        490 
57 
586. 日期相減得到分鐘差 
59 ex. 
60 select trunc((sysdate - to_date('20070901','yyyymmdd'))*24*60) aa from dual; 
61  
62       AA 
63 --------- 
64     29459 
65 
667. 日期相減得到秒數差 
67 ex. 
68 select trunc((sysdate - to_date('20070901','yyyymmdd'))*24*60*60) aa from dual; 
69 
70        AA 
71 ---------- 
72    1767606 
73 
748. 日期 + n小時 
75 ex. 
76 select to_char(sysdate,'YYYY/MM/DD HH24:MI:SS') aa from dual; 
77  
78 AA 
79 -------------------- 
80 2007/09/21 11:03:47  --系統時間 
81  
82 select to_char(sysdate+2/24,'YYYY/MM/DD HH24:MI:SS') aa from dual; 
83 
84 AA 
85 -------------------- 
86 2007/09/21 13:03:47  --加2小時(理論值) 
87 
889. 日期 + n分鐘  
89 ex. 
90 select to_char(sysdate+10/1440,'YYYY/MM/DD HH24:MI:SS') aa from dual; 
91 
92 AA 
93 -------------------- 
94 2007/09/21 11:13:47  --加10分鐘(理論值) 
95 
9610. 日期+ n秒鐘 
97 ex. 
98 select to_char(sysdate+10/86400,'YYYY/MM/DD HH24:MI:SS') aa from dual; 
99     
100 AA 
101 -------------------- 
102 2007/09/21 11:13:57  --加10秒鐘(理論值)