무료하던 나의 일상에 흥미(?)로운 내용을 발견하게 돼 포스팅 하게 된다.

 

2년전쯤 개발한 사이트의 사용자 테이블 암호화 작업을 추가해야 하는데 고객의 급한(?)요구가 있어 관련된 내용이 무엇이 있을까 살펴 보았더니 딱 이거다 하는 내용이 있어 내용을 분석/파악하여 방금전 운영에 반영을 하고 왔다.

 

기존 Password컬럼에 비밀번호가 고스란히 표시가 되었고 이부분을 암호화하여 저장하여 향후 유지관리 될 수 있도록 학는게 목표였는데 MS-SQL에 PWDENCRYPT, PWDCOMPARE 함수를 이용하였다.

사실 좀 아쉬운 점은 암호화는 되지만 복호화 부분이 참일경우 '1', 거짓일 경우 '0' 경우라 제한적인 부분이란 것이다.

로그인이 '1' 일 때는 성공, '0' 일 때는 실패로 처리하여 별 무리 없이 진행은 되었다.(그래도 아쉬워 ㅠ)

 

중요한 점은 Password가 저장될 컬럼이 VARCHAR형태가 아닌 VARBINARY 형태로 저장을 하여야 이용을 할 수 있는 점이 특징이다.

 

개발하랴 유지보수 업무 하랴 바쁘다 바빠 하앍하앍~~

 


CREATE TABLE MEMBER (
 USERID VARCHAR(10),
 USERPASSWORD VARBINARY(100)
);

 

INSERT INTO MEMBER(USERID, USERPASSWORD) VALUES ('aa', PWDENCRYPT('1111'));

 

SELECT USERID, USERPASSWORD, PWDCOMPARE('1111', USERPASSWORD) FROM MEMBER;

=============

aa | 1111 | 1

 

 

참고 사이트 : http://ladon.tistory.com/18


WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

--Create a target table

CREATE TABLE Products

(

ProductID INT PRIMARY KEY,

ProductName VARCHAR(100),

Rate MONEY

GO

--Insert records into target table

INSERT INTO Products

VALUES

(1, 'Tea', 10.00),

(2, 'Coffee', 20.00),

(3, 'Muffin', 30.00),

(4, 'Biscuit', 40.00)

GO

--Create source table

CREATE TABLE UpdatedProducts

(

ProductID INT PRIMARY KEY,

ProductName VARCHAR(100),

Rate MONEY

GO

--Insert records into source table

INSERT INTO UpdatedProducts

VALUES

(1, 'Tea', 10.00),

(2, 'Coffee', 25.00),

(3, 'Muffin', 35.00),

(5, 'Pizza', 60.00)

GO

SELECT * FROM Products

SELECT * FROM UpdatedProducts

GO



MERGE Products AS TARGET

USING UpdatedProducts AS SOURCE 

ON (TARGET.ProductID = SOURCE.ProductID) 

WHEN MATCHED AND TARGET.ProductName <> SOURCE.ProductName 

OR TARGET.Rate <> SOURCE.Rate THEN 

UPDATE SET TARGET.ProductName = SOURCE.ProductName, 

TARGET.Rate = SOURCE.Rate

WHEN NOT MATCHED BY TARGET THEN 

INSERT (ProductID, ProductName, Rate) 

VALUES (SOURCE.ProductID, SOURCE.ProductName, SOURCE.Rate)

WHEN NOT MATCHED BY SOURCE THEN 

DELETE;


----------------------------------------------------------------------------------------------------------------------


Merge 테이블 사용할 기회가 생겨 구글링 해보았음.

좋은 예제인거 같아서 올려봄.


[참고] http://www.mssqltips.com/sqlservertip/1704/using-merge-in-sql-server-to-insert-update-and-delete-at-the-same-time/

[참고] http://msdn.microsoft.com/en-us/library/bb510625.aspx



WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

데이터 정렬 충돌 문제가 발생했단 말이지...


SELECT *

  FROM TABLE_A EI

RIGHT OUTER JOIN TABLE_B URO ON URO.BODY = EI.INFO_BODY

INNER JOIN TABLE_C UMFSD ON URO.FSC = UMFSD.FSC

 WHERE URO.YYYYMMDD = '20120807'

ORDER BY URO.CarDate ASC


위의 쿼리를 날려보니... 아래와 같이 데이터 정렬 충돌했다는 메세지가 뜬다.


Msg 468, Level 16, State 9, Line 4

Cannot resolve the collation conflict between "Chinese_PRC_CI_AI" and "Chinese_PRC_CI_AS" in the equal to operation.


생각없이 내가 DB를 만든 결과이다. 사실 뭐... 어떻게 만들어야한다는 지시가 없었기 때문에 아무생각없이 Default로 DB를 만들었다.
데이터정렬확인하는 것이 기본이긴 하겠지만... 누가 잘못했는지 잘 모르겠다... 그치만 누구의 잘잘못을 떠나 문제 해결이 우선이므로
일단 구글링했다. 답인지는 모르겠지만 결과적으로 해결을 하게 돼 현재까지는 이게 최선의 방법이라고 생각한다.

SELECT *
  FROM TABLE_A EI
RIGHT OUTER JOIN TABLE_B URO ON URO.BODY = EI.INFO_BODY collate Chinese_PRC_CI_AS
INNER JOIN TABLE_C UMFSD ON URO.FSC = UMFSD.FSC
 WHERE URO.YYYYMMDD = '20120807'
ORDER BY URO.CarDate ASC

위의 쿼리에 'collate Chinese_PRC_CI_AS' 이 부분을 추가하여 간단하게 해결했다.


WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

프로세스 마스터를 구성해 보았다.

쓰레드 기반의 각 프로세스별 구동하기 위한 마스터 개념이다.

혹시 각 프로세스별 모니터링이 필요할지 몰라 모니터링에 관련에 항목도 포함시켜 보았다.

향후 사용하면 더 필요한 부분 필요하지 않은 부분을 보완해 나가면서 사용해 나가야겠다.



-- CREATE TABLE PROCESS_MASTER


CREATE TABLE PROCESS_MASTER

(

     PROCESS_ID         VARCHAR(020) NOT NULL

   , PROCESS_DESC      VARCHAR(200)     NULL

   , PROCESS_STATUS    CHAR(1)      DEFAULT 'Y'

   , PROCESS_CYCLE    INT          DEFAULT 1000

   , PROCESS_TYPE      CHAR(1)      DEFAULT 'A'

   , PROCESS_AUTOSTART CHAR(1)      DEFAULT 'N'

   , EXECUTE_CYCLE    INT          DEFAULT 30000

   , EXECUTE_TIME      DATETIME         NULL

   , MONITOR_USE      CHAR(1)      DEFAULT 'Y'

   , MONITOR_STATUS    CHAR(1)      DEFAULT 'A'

   , MONITOR_MSG      VARCHAR(200)     NULL

   , RESERV01          VARCHAR(020)     NULL

   , RESERV02          VARCHAR(020)     NULL

   , RESERV03          VARCHAR(020)     NULL

   , RESERV04          VARCHAR(020)     NULL

   , RESERV05          VARCHAR(020)     NULL

   , INPUT_DATE        DATETIME         DEFAULT GETDATE()

   , INPUT_USER        VARCHAR(020)     NULL

   , UPDATE_DATE      DATETIME         NULL

   , UPDATE_USER        VARCHAR(020)     NULL             

   , CONSTRAINT PK_PROCESS_MASTER PRIMARY KEY CLUSTERED 

    (

    PROCESS_ID

    )

)


--SELECT *  INTO PROCESS_MASTER_BK FROM PROCESS_MASTER



WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

SELECT a.*

FROM OPENROWSET('Microsoft.Jet.OLEDB.4.0','excel 8.0;database=c:\book1.xls;admin;', Sheet1$) 

AS a

GO


-- 아래의 그림과 같이 확인할 수 있다.

-- 단, 엑셀파일이 OPEN 상태에서는 


Msg 7399, Level 16, State 1, Line 1

The OLE DB provider "Microsoft.Jet.OLEDB.4.0" for linked server "(null)" reported an error. The provider did not give any information about the error.

Msg 7303, Level 16, State 1, Line 1

Cannot initialize the data source object of OLE DB provider "Microsoft.Jet.OLEDB.4.0" for linked server "(null)".


-- 위와 같은 에러메세지가 나오니 엑셀파일을 닫고 테스트 해야함.






-- 다음 예에서는 모든 구성 옵션을 설정하고 나열하는 방법을 보여 줍니다. 먼저 show advanced option을 1로 설정하면 고급 구성 옵션이 표시됩니다. 

-- 이 옵션을 변경한 다음 매개 변수 없이 sp_configure를 실행하면 모든 구성 옵션이 표시됩니다.

sp_configure 'show advanced options', 1  

RECONFIGURE  

GO  


--------------------------------------------------------------------------------------------------------------------------------------

--메시지 15281, 수준 16, 상태 1, 줄 1

--구성 요소 'Ad Hoc Distributed Queries'이(가) SQL Server 보안 구성의 일부로 해제되었으므로 

--이 구성 요소의 문 'OpenRowset/OpenDatasource'에 대한 액세스가 차단되었습니다.

-- 시스템 관리자는 sp_configure를 사용하여 'Ad Hoc Distributed Queries'의 사용을 활성화할 수 있습니다. 

-- 'Ad Hoc Distributed Queries' 활성화 방법은 SQL Server 온라인 설명서의 "노출 영역 구성"을 참조하십시오.

 

[ 해결방법 ]

 

sp_configure 'show advanced options',1;

go

reconfigure ; 

go

sp_configure  'Ad Hoc Distributed Queries', 1

go 

reconfigure ;

go

[출처] MS-SQL OPENROWSET 사용하기|작성자 불가사리

--------------------------------------------------------------------------------------------------------------------------------------

 







WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

-- sys.dm_db_index_physical_stats(Transact-SQL)

-- http://technet.microsoft.com/ko-kr/library/ms188917.aspx


-- 1.지정한 테이블에 대한 정보 반환

DECLARE @db_id SMALLINT;

DECLARE @object_id INT;


SET @db_id = DB_ID(N'testDB');

SET @object_id = OBJECT_ID(N'testDB.dbo.t3');


IF @db_id IS NULL

BEGIN;

    PRINT N'Invalid database';

END;

ELSE IF @object_id IS NULL

BEGIN;

    PRINT N'Invalid object';

END;

ELSE

BEGIN;

    SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, NULL, NULL , 'LIMITED');

END;

GO


-- 2.모든 데이터베이스에 대한 정보 반환

SELECT * FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, NULL);

GO


-- 3.스크립트에 sys.dm_db_index_physical_stats를 사용하여 인덱스를 다시 작성하거나 다시 구성

--   다음 예에서는 데이터베이스에서 평균 조각화가 10%를 넘는 모든 파티션을 자동으로 다시 구성하거나 다시 작성합니다. 이 쿼리를 실행하려면 VIEW DATABASE STATE 권한이 필요합니다


-- Ensure a USE <databasename> statement has been executed first.

SET NOCOUNT ON;

DECLARE @objectid int;

DECLARE @indexid int;

DECLARE @partitioncount bigint;

DECLARE @schemaname nvarchar(130); 

DECLARE @objectname nvarchar(130); 

DECLARE @indexname nvarchar(130); 

DECLARE @partitionnum bigint;

DECLARE @partitions bigint;

DECLARE @frag float;

DECLARE @command nvarchar(4000); 

-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function 

-- and convert object and index IDs to names.

SELECT

    object_id AS objectid,

    index_id AS indexid,

    partition_number AS partitionnum,

    avg_fragmentation_in_percent AS frag

INTO #work_to_do

FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED')

WHERE avg_fragmentation_in_percent > 10.0 AND index_id > 0;


-- Declare the cursor for the list of partitions to be processed.

DECLARE partitions CURSOR FOR SELECT * FROM #work_to_do;


-- Open the cursor.

OPEN partitions;


-- Loop through the partitions.

WHILE (1=1)

    BEGIN;

        FETCH NEXT

           FROM partitions

           INTO @objectid, @indexid, @partitionnum, @frag;

        IF @@FETCH_STATUS < 0 BREAK;

        SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name)

        FROM sys.objects AS o

        JOIN sys.schemas as s ON s.schema_id = o.schema_id

        WHERE o.object_id = @objectid;

        SELECT @indexname = QUOTENAME(name)

        FROM sys.indexes

        WHERE  object_id = @objectid AND index_id = @indexid;

        SELECT @partitioncount = count (*)

        FROM sys.partitions

        WHERE object_id = @objectid AND index_id = @indexid;


-- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.

        IF @frag < 30.0

            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';

        IF @frag >= 30.0

            SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';

        IF @partitioncount > 1

            SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS nvarchar(10));

        EXEC (@command);

        PRINT N'Executed: ' + @command;

    END;


-- Close and deallocate the cursor.

CLOSE partitions;

DEALLOCATE partitions;


-- Drop the temporary table.

DROP TABLE #work_to_do;

GO


-- 4. sys.dm_db_index_physical_stats를 사용하여 페이지 대 압축된 페이지 수 표시

SELECT o.name,

    ips.partition_number,

    ips.index_type_desc,

    ips.record_count, ips.avg_record_size_in_bytes,

    ips.min_record_size_in_bytes,

    ips.max_record_size_in_bytes,

    ips.page_count, ips.compressed_page_count

FROM sys.dm_db_index_physical_stats ( DB_ID(), NULL, NULL, NULL, 'DETAILED') ips

JOIN sys.objects o on o.object_id = ips.object_id

ORDER BY record_count DESC;



-- 5.SAMPLED 모드에서 sys.dm_db_index_physical_stats 사용

--   다음 예에서는 SAMPLED 모드가 DETAILED 모드 결과와 다른 대략적인 값을 어떻게 반환하는지를 보여 줍니다.

CREATE TABLE t3 (col1 int PRIMARY KEY, col2 varchar(500)) WITH(DATA_COMPRESSION = PAGE);

GO

BEGIN TRAN

DECLARE @idx int = 0;

WHILE @idx < 1000000

BEGIN

    INSERT INTO t3 (col1, col2) 

    VALUES (@idx, 

    REPLICATE ('a', 100) + CAST (@idx as varchar(10)) + REPLICATE ('a', 380))

    SET @idx = @idx + 1

END

COMMIT;

GO

SELECT page_count, compressed_page_count, forwarded_record_count, * 

FROM sys.dm_db_index_physical_stats (db_id(), 

    object_id ('t3'), null, null, 'SAMPLED');

SELECT page_count, compressed_page_count, forwarded_record_count, * 

FROM sys.dm_db_index_physical_stats (db_id(), 

    object_id ('t3'), null, null, 'DETAILED');


WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,

-----------구구단--------------

declare @a int, @dan int

set @dan = 2

while @dan < 10

begin

   set @a = 1

   while @a < 10

   begin

      print str(@dan) + ' x ' +str(@a) + ' = ' + str(@dan * @a)

      set @a = @a+1

   end

   print ''

   set @dan = @dan + 1

end 

set @a = 1

print '끝'


[참조] http://j.finfra.com/zbl/?document_srl=3545&mid=lecMsSqlLecdata&sort_index=readed_count&order_type=asc

의 내용을 약간 변경함



WRITTEN BY
테네시왈츠
항상 겸손하게 항상 새롭게 항상 진실하게

,