27 พฤศจิกายน 2568
Toyota New Fortuner เมื่อแอร์ไม่เย็น มีลมร้อนจากฮีตเตอร์
25 พฤศจิกายน 2568
SQL Server : Stored Procedure for Backup day of week
สำหรับท่านที่ต้องการสำรองข้อมูลของฐานข้อมูล SQL Server โดยสำรองแล้วตั้งชื่อตามวันในสัปดาห์ ก็สามารถสร้าง Stored Procedure ไว้ภายใต้ฐานข้อมูล master ตามตัวอย่างด้านล่าง
USE master
GO
/*
Programmer : Kasem K.
Create : 12/11/2006
-- Execute the generated SQL command
Sample
======
EXEC sp_BackupDatabase
@databaseName='yourDatabaseName',
@backupType='F',
@backupLocation='D:\BackupFolder'
GO
*/
CREATE PROCEDURE [dbo].[sp_BackupDatabase]
@databaseName varchar(300),
@backupType CHAR(1), -- F = full bakcup D = difference backup
@backupLocation nvarchar(200)
AS
DECLARE @BackupName varchar(200)
DECLARE @BackupFile varchar(200)
DECLARE @sqlCommand nvarchar(4000)
DECLARE @DayOfWeek varchar(10)
SET @DayOfWeek = DATENAME(dw,GETDATE())
-- Create backup filename in path\filename.extension format for full and diff backups
-- Generate the dynamic SQL command to be executed
IF @backupType = 'F'
BEGIN
SET @BackupFile = @backupLocation + '\' +
REPLACE(REPLACE(@databaseName, '[',' '),']',' ') +
'_' + @dayOfWeek + '.BAK'
SET @BackupName = REPLACE(REPLACE(@databaseName,'[',' '),']',' ') +
' full backup for ' + @DayOfWeek
SET @sqlCommand = 'BACKUP DATABASE ' + @databaseName +
' TO DISK = ''' + @BackupFile + '''' +
' WITH INIT, NAME = ''' + @BackupName + '''' +
', NOSKIP, NOFORMAT'
-- ใช้ INIT: สร้างไฟล์ใหม่ทับไฟล์เดิม
-- ใช้ NOFORMAT: เก็บแบ็กอัพใหม่เพิ่มเข้าไปใน media set เดิม
-- ใช้ FORMAT: สร้าง media set ใหม่ ลบข้อมูลเดิมออก
EXEC(@sqlCommand)
END
ELSE IF @backupType = 'D'
BEGIN
SET @BackupFile = @backupLocation + '\' +
REPLACE(REPLACE(@databaseName, '[',' '),']',' ') +
'_' + @DayOfWeek + '.BAK'
SET @BackupName = REPLACE(REPLACE(@databaseName,'[',' '),']',' ') +
' differential backup for '+ @DayOfWeek
SET @sqlCommand = 'BACKUP DATABASE ' + @databaseName +
' TO DISK = ''' + @BackupFile + '''' +
' WITH INIT, NAME = ''' + @BackupName + '''' +
', NOSKIP, NOFORMAT'
EXEC(@sqlCommand)
END
19 มิถุนายน 2567
NET : Visual Studio Code กับการติดตั้ง Extension และการสร้าง Project .Net Blazor
ให้ทำการติดตั้ง Visual Code จากนั้นให้ทำการติดตั้ง Extension ชื่อ C# Dev Kit
เปิด Terminal โดยเลือกเมนู View -> Terminal
ดู Version .net
dotnet --version
ดู รายละเอียด Template
dotnet new list
ดู Information ของ .net
dotnet --info
การสร้าง Project
ให้ เปิด Explorer (เมนู View -> Explorer)
คลิกเมาส์ขวาที่ว่าง ๆ ของ Explorer เลือก New Floder... แล้วสร้างโฟลดเดอร์ตามต้องการ เช่น myAPP
จากนั้นไปที่เมนู View -> Command Pallette....
ที่ช่อง Command Pallette ให้พิมพ์ .NET: จากนั้นเลือก New Project...
เลือก Blazor Web App แล้วตั้งชื่อตามต้องการ เช่น myApp.Frontend
เปิด Solution Explorer แล้วใส่ project เข้าไป ทำการ build จะสร้างไฟล์ dll exe ... ภายใต้ โฟลดเดอร์ bin\debug\net8.0
เมื่อ build เสร็จ จะทดสอบ ให้กด F5 ที่ แล้วเลือก C# แล้วเลือกรายการที่เป็น [http]
ก็จะปรากฎเว็บไซต์ที่สร้างขึ้น
14 กุมภาพันธ์ 2567
Visual FoxPro : การใช้ BindEvent
หลาย ๆ ครั้งเราอยากจะตรวจสอบเหตุการณ์ (event) ที่เกิดขึ้นใน Visual FoxPro 9 แต่บางเหตุการณ์ดันไม่มี method ของเหตุการณ์นั้นมารองรับ เช่น VFP มีแต่ KeyPress Event เป็นเหตุการณ์สำหรับตรวจสอบการกดปุ่มบนคีย์บอรด์อย่างเดียวเลย แต่..ถ้าเราอยากจะตรวจสอบเฉพาะตอนกดปุ่ม (KeyDown) หรือเฉพาะตอนปล่อยปุ่ม (KeyUp) จะทำไงละ แต่...คนสร้าง VFP ก็ช่างคิดเสียนี่กระไร ในเมื่อฉันไม่ได้เตรียม event/method ไว้ให้ แต่ก็ทิ้งคำสั่ง BindEvent เอาไว้ให้แทน
มาดูตัวอย่างการทำฟอร์มให้สามารถใช้งาน การตรวจสอบการกดปุ่ม (KeyDown) และปล่อยปุ่ม (KeyUp) (ตัวอย่างนี้มาจากคำถามของสมาชิกชาว Fox จะป้องกัน user กดปุ่มค้างไม่ยอมปล่อย ดังนั้นถ้าไปเช็คใน KeyPress Event มันวิ่งตลอด ที่เขียนโปรแกรมทำอะไรไว้วิ่งเป็นพรวน....) ดังนั้น การตรวจสอบ KeyDown KeyUp จะได้มันใจว่ากดยาว กดแช่ กดสั้น กดไว อย่างไรก็ทำครั้้งเดียวจนกว่าจะกดใหม่
สำหรับตัวอย่างนี้สามารถใช้เป็นแนวทางในการทำ BindEvent กับเหตุการอื่น ๆ ได้อีกมากมาย นะจ๊ะ...
1. ให้สร้างฟอร์มขึ้นมาใหม่ จากนั้นไปที่เมนู Form -> New Method จะปรากฎหน้าต่าง New Method
- ที่ช่อง Name ป้อน KeyDown แล้วคลิกปุ่ม Add
- ที่ช่อง Name ป้อน KeyUp แล้วคลิกปุ่ม Add
2. ไปป้อนคำสั่งที่ฟอร์มในเมธอด ดังนี้
- เมธอด Init ป้อนคำสั่ง
* สร้างตัวแปรฟอร์มสำหรับตรวจสอบการกดปุ่มค้าง
=ADDPROPERTY(ThisForm, "nPreventKeyPress",0)
* ทำการผูกการกดคีย์(keydown)(เลข 256) กับ object ฟอร์ม(This) เรียกเมธอด KeyDown
=BINDEVENT(0, 256, This, "KeyDown")
* ทำการผูกการกดคีย์(keydown)(เลข 257) กับ object ฟอร์ม(This) เรียกเมธอด KeyUp
=BINDEVENT(0, 257, This, "KeyUp")
ดูความหมายของค่าตัวเลข 256 257 หรืออื่น ๆ ของ Windows Message ที่ส่งมา https://wiki.winehq.org/List_Of_Windows_Messages
26 มกราคม 2567
Vฺisual Studio 2022 C# Blazor - 01
// youtube : https://youtu.be/dY_AWdCzsCY?si=eQyqwMcRINbhvUYz
// index.razor
@page "/"
@rendermode InteractiveServer
<h3>Hello, @userName</h3>
<h3>@GetUserName()</h3>
<p>Sum : @GetSum()</p>
<button @onclick = "ChgName">Change Name</button>
@if (testNum == 1)
{
<p>Num is 1</p>
} else {
<p>Num is not 1</p>
}
@foreach(var name in names)
{
<p>@((MarkupString)name)</p>
}
@code {
private string userName = "John";
private int testNum = 10;
private List<string> names;
private string GetUserName()
{
return userName + "ซำบายดีไหม?";
}
private int GetSum()
{
return 2 + 2 + 3;
}
private void ChgName()
{
userName = "เกษม";
}
protected override void OnInitialized()
{
base.OnInitialized();
names = new List<string>
{
"<b>Value 01<b>",
"Value 02",
"Value 03",
"Value 04",
"Value 05",
"<i>Value 06<i>",
"Value 07",
"Value 08",
"Value 09",
"Value 10"
};
}
}
14 กุมภาพันธ์ 2566
SQL Server : CTEs (Common Table Expressions)
Common Table Expressions หรือ CTEs เริ่มถูกนำมาใช้ใน SQL Server 2005 เป็นครั้งแรก โดยที่ CTE นั้นเป็นผลลัพท์ที่เป็นตารางชั่วคราว ซึ่งสามารถนำไปอ้างหรือใช้งานภายใต้คำสั่งคิวรี่ SELECT INSERT UPDATE หรือ DELETE ใน SQL Server 2008 ได้เพิ่มความสามารถให้ใช้ CTE ในคำสั่ง MERGE ได้ การใช้งาน CTE เริ่มด้วยการใช้ WITH
WITH ชื่อตาราง_CTE
AS
(
คำสั่ง Query ผลลัพธ์ของคิวรีที่ได้จะไปเก็บใน ชื่อตาราง_CTE
)
คำสั่ง Query ที่เรียกใช้งานตาราง CTE
กรณีที่สร้างหลาย CTE ก็ให้เพิ่มโดยใส่ , (คอมม่า) แล้วก็ชื่อตารางตามตัวอย่าง
WITH ชื่อตาราง_CTE_1
AS
(
คำสั่ง Query ผลลัพธ์ของคิวรีที่ได้จะไปเก็บใน ชื่อตาราง_CTE_1
) ,
ชื่อตาราง_CTE_2
AS
(
คำสั่ง Query ผลลัพธ์ของคิวรีที่ได้จะไปเก็บใน ชื่อตาราง_CTE_2
และสามารถเรียกใช้ตาราง CTE_1 ได้ด้วย
)
คำสั่ง Query ที่เรียกใช้งานตาราง CTE
รูปแบบคำสั่งแค่นี้ก็เราก็สามารถแปรกระบวนท่าในการเขียนจัดการคำสั่งคิวรีได้มากมาย
ตัวอย่าง
WITH CTE AS (
SELECT dd.Driver_no, COUNT(dd.Do_Date) Total_day
FROM (SELECT DISTINCT Driver_no, Do_Date
FROM DoDriver WHERE MYear = '2022' AND MPeriod = '12') dd
GROUP BY dd.Driver_no
)
SELECT d.*, c.Total_Day FROM CTE c
LEFT JOIN (
SELECT d.Driver_no, d.Driver_name, SUM(d.Qty_do) Tot_do
,SUM(d.Z_Q_tot) Total_QTY_G
,SUM(d.Z_T_tot + d.Z_Trip_E1 ) as Total_WAGE
,COUNT(d.Do_no) Total_trip, SUM(d.Z_T_tot) Total_T_tot
,SUM(d.Z_Trip_E1) AS Total_E1, SUM(d.Z_Trip_E2) AS Total_E2
,SUM(d.Z_Trip_E3) AS Total_E3, SUM(d.Z_Trip_E4) AS Total_E4
, SUM(d.Z_Trip_E5) AS Total_E5
FROM DoDriver d WHERE d.MYear = '2022' AND d.MPeriod = '12'
GROUP BY d.Driver_no, d.Driver_name
) AS d
ON c.Driver_no = d.Driver_no
ตัวอย่าง
WITH CTE AS (
SELECT RowOrder, MYear, MPeriod, Driver_no, Do_date, Do_Time
, ROW_NUMBER() OVER(PARTITION BY Driver_no, Do_Date
ORDER BY Driver_no, Do_Date, Do_time) AS Trip_of_D
, ROW_NUMBER() OVER(PARTITION BY Driver_no
ORDER BY Driver_no,Do_Date, Do_time) AS Trip_of_M
FROM DoDriver
WHERE MYear = '2022' AND MPeriod = '20212'
AND Driver_no = '0001' )
SELECT c.*,c1.Trip_sum_M FROM CTE c
LEFT JOIN (SELECT Driver_no, COUNT(*) AS Trip_sum_M
FROM CTE
GROUP BY Driver_no) c1
ON c.Driver_no = c1.Driver_no
จริง ๆ มัน เหมือน ๆ กับทำ subquery แต่มันจะเอามายำ ๆ ๆ ๆ ยำไปยำมาก่อน แล้วสุดท้ายเอาไปใช้งาน ได้ผลตามต้องการ ดูง่ายไล่สะดวก
เอาไว้เป็นไอเดีย การทดลองทำจะทำให้เข้าใจมากยิ่งขึ้น
09 พฤศจิกายน 2565
SQL Server : OUTER APPLY and CROSS APPLY
หลายคนคงเคยใช้คำสั่ง JOIN เพื่อทำการเชื่อมโยงตารางตั้งแต่ 2 ตารางขึ้นไป แล้วให้ได้ผลลัพธ์ที่ต้องการ แต่มีคำสั่ง APPLY ที่ทำงานได้ลักษณะเดียวกันกับ JOIN แต่มีความคล่องตัวและยืดหยุ่นกว่า ซึ่งจริง ๆ แล้วคำสั่ง APPLY เกิดขึ้นมานานมากตั้งแต่ SQL Server 2005 การทำงานจะเหมือนการใช้งานคำสั่ง JOIN แต่จะแตกต่างกันตรงที่ตารางด้านขวาของ APPLY สามารถประมวลผลภายใต้เงื่อน where ไขของตารางด้านซ้ายได้ หรือสามารถเขียนเป็น table-value function แล้วส่งค่ากลับมาเชื่อมโยงกับตารางฝั่งซ้ายมือก็ได้ เป็นต้น
การใช้ APPLY หลัก ๆ จะใช้อยู่ 2 แบบคือ OUTER APPLY กับ CROSS APPLY โดยที่
OUTER APPLY เปรียบได้กับการใช้ LEFT JOIN
CROSS APPLY เปรียบได้กับการใช้ INNER JOIN
ดังนั้นการนำไปใช้งาน สามารถเลือกใช้ได้ตามความเหมาะสม
หลายท่านคงมีคำถามในใจ แล้วเราจะเอาไปประยุกต์ใช้ในงานใดได้บ้าง
ดังนั้น : ขอยกตัวอย่าง สัก 2 - 3 ตัวอย่าง เพื่อให้พอเห็นภาพ เพื่อท่าน ๆ จะได้นำไปประยุกต์ใช้ได้ตามต้องการ
ตัวอย่าง การใช้คำสั่ง JOIN เปรียบเทียบกับการใช้คำสั่ง APPLY
SELECT p.[prod_no], p.[prod_name], t1.[in_min], t1.[in_max], t2.[in_last]
FROM [Products] p
OUTER APPLY (
SELECT MIN(t.[qty]) in_min, MAX(t.[qty]) in_max
FROM [Transactions] t
WHERE t.type = 'IN' AND t.[prod_no] = p.[prod_no] GROUP BY t.[prod_no]
) t1
OUTER APPLY (
SELECT TOP 1 t.[qty] in_last
FROM [Transactions] t
WHERE t.type = 'IN' AND t.[prod_no] = p.[prod_no] ORDER BY t.[tran_id] DESC
) t2
02 พฤศจิกายน 2565
SQL SERVER : UPDATE JOIN
มีอยู่วันหนึ่งไปเจอคำถาม ซึ่งไม่เกี่ยวกับผู้เขียน แต่อดที่จะตอบไม่ได้
"ผมจะใช้คำสั่ง SQL เพื่อ Update Table A โดยเอายอดรวมจาก Select sum ของ Table B ไปใส่ใน Table A ที่มี Key ตรงกันกับ Table B ได้อย่างไรครับ"
คำถามแบบนี้ชอบที่ยื่นมือเข้าไปตอบ ถ้าพูดภาษาชาวบ้านเขาเรียกว่า เสือก 555
การกระทำแบบนี้ สามารถใช้คำสั่ง SQL ได้หลายตัว เช่น UPDATE Join หรือ MERGE ก็ได้
แต่.... คำถาม ต้องการแค่ปรับปรุงยอดรวมเฉย ๆ ก็เลยใช้ UPDATE ร่วมกับ JOIN แทนการใช้คำสั่ง MERGE แต่คำสั่ง MERGER จริง ๆ แล้วทำอะไรได้มากกว่า มันสามารถ INSERT, UPDATE, DELETE จากแหล่งข้อมูลอื่นมาใส่ตารางเป้าหมายได้ในคำสั่งเดียวเลย อ้าว... นอกเรื่องอีกแล้ว
จากที่เดาข้อคำถาม เข้าใจว่าคงเป็นการปรับปรุงยอดบางอย่าง เช่น ยอดสินค้าคงเหลือ ยอดเงินคงเหลือ หรือยอดลูกหนี้คงค้าง เป็นต้น
เพื่อให้เห็นภาพ จะขอยกตัวอย่างการปรับปรุงยอดสต๊อกสินค้า จากรายการรับ/จ่ายที่เกิดขึ้น
ให้สร้างตารางเพื่อทดสอบ ดังนี้
สร้างตาราง Products
CREATE TABLE [Products] (
[prod_no] [nchar](10) NOT NULL,
[prod_name] [nvarchar](100),
[onhand] [numeric](10, 0),
PRIMARY KEY ([prod_no]))
สร้างตาราง Transactions สำหรับเก็บรายการ รับ/จ่าย สินค้า
CREATE TABLE [Transactions] (
[tran_id] [int] IDENTITY(1,1) NOT NULL,
[prod_no] [nchar](10),
[type] [nchar](3),
[qty] [numeric](10, 0),
PRIMARY KEY ([tran_id]))
ทำการเพิ่มข้อมูลตัวอย่างเข้าสู่ตาราง
INSERT INTO [Products] VALUES ('001','วิทยุทรานซิสเตอร์ ธานินทร์',0),
('002','ถ่านไฟฉาย ตรากบ',0),
('003','ยาแก้ปวด ทันใจ',0),
('004','บะหมี่กึ่งสำเร็จรูป มาม่า',0),
('005','นมข้นหวาน ตราหมี',0) ;
INSERT INTO [Transactions] VALUES('001','IN',20),
('003','IN',10),
('002','IN',100),
('005','IN',50),
('002','OUT',10),
('001','OUT',1),
('001','OUT',2),
('003','IN',15),
('003','OUT',10),
('001','OUT',2) ;
หลังจากทำการเพิ่มข้อมูลเรียบร้อยแล้ว ลองทำการคิวรีข้อมูลออกมาแสดงจะได้ ดังนี้
SELECT * FROM [Products]
SELECT * FROM [Transactions]
ให้ผู้อ่านลองดูข้อมูลในตาราง Transactions จะเห็นว่าข้อมูลจะมีคอลัมน์ type ซึ่งเก็บสถานะการรับ (in) และจ่าย (out) หากเราจะหาผลรวมที่เป็นยอดคงเหลือโดยใช้คำสั่ง SUM(qty) ก็จะมีปัญหาเนื่องจากยอดในคอลัมน์ qty มีค่าเป็นบวกหมด ดังนั้นเราต้องทำการแปลงเป็นค่า บวก หรือ ลบ โดยถ้า type มีค่าเป็น IN ให้ยอด qty มีค่าเป็นบวก แต่ถ้า type มีค่าเป็น OUT ก็ให้ยอด qty มีค่าเป็นลบ เพื่อจะได้หายอดคงเหลือของการรับ/จ่ายได้ สามารถเขียนคำสั่งได้ ดังนี้
SELECT * FROM [Transactions] ORDER BY [prod_no], [type]
SELECT [prod_no], SUM(CASE WHEN [type]='IN' THEN [qty] ELSE [qty] * -1 END) AS [onhand] FROM [Transactions] GROUP BY [prod_no]
จากคำสั่ง SUM(CASE WHEN [type]='IN' THEN [qty] ELSE [qty] * -1 END) ข้างต้นที่เราจะได้ยอดคงเหลือมาแสดงเรียบร้อย
ขั้นต่อมาคือนำไปปรับปรุงยอดในคอลัมน์ onhand ของตาราง Products ซึ่งการทำเราจะใช้คำสั่ง UPDATE ร่วมกับ JOIN เพื่อปรับปรุงยอด ดังนี้
--ปรับปรุงข้อมูลตาราง Products ในคอลัมน์ onhand จากยอด SUM ของตาราง Transactions
UPDATE P SET P.[onhand] = T.[onhand]
FROM [Products] P
INNER JOIN (SELECT [prod_no], SUM(CASE WHEN [type]='IN' THEN [qty] ELSE [qty] * -1 END) AS [onhand]
FROM [Transactions] GROUP BY [prod_no]) T
ON P.[prod_no] = T.[prod_no]
--แสดงยอดที่ปรับปรุงแล้วของตาราง Products
SELECT * FROM [Products]
จะเห็นว่าการใช้ UPDATE JOIN ช่วยได้มากเลย คำสั่ง SQL เชื่อมโยงรหัส (prod_no) ที่ตรงกันแล้วทำกันปรับปรุงยอดให้ทำให้เรามันใจว่าอย่างไรเสียข้อมูลไม่มีวันผิดพลาด
สวัสดี ผลสลากกินแบ่ง งวด 1 พย. 65 รางวัลที่ 1 ..... 913106
15 กรกฎาคม 2565
SQL Server : Dynamic PIVOT in SQL Server
PIVOT ใน SQL Server คือเครื่องมือที่ช่วยสร้างตารางสรุปในรูปแบบการเปลี่ยนการแสดงผลจากแนวตั้ง (Row) มาเป็นแนวนอน (Column) ซึ่งช่วยให้การดูข้อมูลสะดวกมากยิ่งขึ้น แต่เนื่องจาก การทำ PIVOT ใน SQL Server จำเป็นต้องทราบข้อมูลที่จะนำมาใช้เป็นชื่อคอลัมน์ในแนวนอนที่แน่นอน ซึ่งเหมาะกับการทำสรุป ยอดขายประจำเดือน ซึ่งมีแค่ เดือน 1 ถึงเดือน 12 หรือการสรุปตามวัน ซึ่งมี 1 - 31 ไม่เกินนี้ แต่ถ้าหากข้อมูลเรามีการเพิ่มลดอย่างต่อเนื่อง (แต่ต้องไม่มากจนเกินไป) จำเป็นต้องใช้วิธีการเขียนคำสั่งเพื่อทำให้ PIVOT สามารถแสดงผลเป็นแบบ Dynamic ได้ตามต้องการ
สำหรับตัวอย่างที่จะนำเสนอเป็นการสรุปยอด ตาม Category ของสินค้า ซึ่งจะแยกเป็นยอดขายแต่ละวัน โดยใช้ตาราง Category เป็นตารางที่จะนำมาเป็นตัวที่ทำ PIVOT ในส่วนของคอลัมน์ ซึ่งจะผันแปรไปตามข้อมูลที่มีอยู่ในตาราง Category ตาราง Product เก็บรายการสินค้า และ ตาราง Inv_dtl เก็บข้อมูลการขายสินค้า ตาราง inv_hd เก็บวันที่ขาย รายละเอียด ดังภาพ
ตัวอย่างตารางและข้อมูล
CREATE TABLE [category](
[cat_id] [nchar](10) NULL,
[cat_name] [nvarchar](50) NULL
)
CREATE TABLE [inv_dtl](
[inv_no] [nchar](10) NULL,
[product_id] [nchar](10) NULL,
[qty] [money] NULL,
[price] [money] NULL,
[amount] [money] NULL
)
CREATE TABLE [inv_hd](
[inv_no] [nchar](10) NULL,
[inv_date] [date] NULL
)
CREATE TABLE [product](
[product_id] [int] NULL,
[product_name] [varchar](50) NOT NULL,
[cat_id] [varchar](25) NULL
)
GO
INSERT [category] ([cat_id], [cat_name]) VALUES (N'C01', N'Beverage')
INSERT [category] ([cat_id], [cat_name]) VALUES (N'C02', N'Beauty')
INSERT [category] ([cat_id], [cat_name]) VALUES (N'C03', N'Health')
INSERT [category] ([cat_id], [cat_name]) VALUES (N'C04', N'Food')
INSERT [inv_dtl] ([inv_no], [product_id], [qty], [price], [amount]) VALUES (N'65001', N'101', 5.0000, 200.0000, 100.0000)
INSERT [inv_dtl] ([inv_no], [product_id], [qty], [price], [amount]) VALUES (N'65002', N'105', 1.0000, 80.0000, 80.0000)
INSERT [inv_dtl] ([inv_no], [product_id], [qty], [price], [amount]) VALUES (N'65002', N'104 ', 2.0000, 70.0000, 140.0000)
INSERT [inv_dtl] ([inv_no], [product_id], [qty], [price], [amount]) VALUES (N'65003', N'102', 3.0000, 50.0000, 150.0000)
INSERT [inv_dtl] ([inv_no], [product_id], [qty], [price], [amount]) VALUES (N'65003', N'104', 2.0000, 70.0000, 140.0000)
INSERT [inv_dtl] ([inv_no], [product_id], [qty], [price], [amount]) VALUES (N'65004', N'102', 2.0000, 80.0000, 160.0000)
INSERT [inv_dtl] ([inv_no], [product_id], [qty], [price], [amount]) VALUES (N'65005', N'101', 2.0000, 200.0000, 400.0000)
INSERT [inv_hd] ([inv_no], [inv_date]) VALUES (N'65001', CAST(N'2022-05-22' AS Date))
INSERT [inv_hd] ([inv_no], [inv_date]) VALUES (N'65002', CAST(N'2022-05-22' AS Date))
INSERT [inv_hd] ([inv_no], [inv_date]) VALUES (N'65003', CAST(N'2022-05-23' AS Date))
INSERT [inv_hd] ([inv_no], [inv_date]) VALUES (N'65004', CAST(N'2022-05-24' AS Date))
INSERT [inv_hd] ([inv_no], [inv_date]) VALUES (N'65005', CAST(N'2022-05-24' AS Date))
INSERT [product] ([product_id], [product_name], [cat_id]) VALUES (1, 101, N'Soda', N'C01')
INSERT [product] ([product_id], [product_name], [cat_id]) VALUES (2, 102, N'Water', N'C01')
INSERT [product] ([product_id], [product_name], [cat_id]) VALUES (3, 103, N'Pork', N'C04')
INSERT [product] ([product_id], [product_name], [cat_id]) VALUES (4, 104, N'Vegetable', N'C04')
INSERT [product] ([product_id], [product_name], [cat_id]) VALUES (5, 105, N'Fruit', N'C04')
จากตารางข้างต้นถ้าเราจะทำรายงานสรุป ยอดขายตาม Category โดยแยกเป็นแต่ละวัน สามารถทำได้โดยใช้คำสั่ง
SELECT h.inv_date,c.cat_id,SUM(i.amount) as Total FROM inv_dtl i
LEFT JOIN inv_hd h ON i.inv_no = h.inv_no
LEFT JOIN product p ON i.product_id = p.product_id
LEFT JOIN category c ON p.cat_id = c.cat_id
GROUP BY c.cat_id,h.inv_date
ORDER BY h.inv_date,c.cat_id
จะได้ผลลัพธ์ดังภาพ
จะเห็นว่าข้อมูลข้างต้นจะเป็นข้อมูลสรุปยอดขายตาม Category โดยแยกสรุปเป็นวัน แต่เป็นรายการในลักษณะแนวตั้ง การดูรายงานจะทำให้เข้าใจได้ยาก หากต้องการนำเสนอในรูปแบบสรุป จำเป็นต้องอาศัยการใช้งานคำสั่ง PIVOT เพื่อกลับตารางจากแนวตั้งเป็นแนวนอน
แต่สิ่งที่เป็นโจทย์ในบทความนี้คอ ต้องนำรายการของ Category ทั้งหมด มาแสดงเป็นหัวคอลัมน์ ดังนั้นต้องนำข้อมูลในตาราง Category ทั้งหมดมาแปลงก่อนนำไปใช้ในคำสั่ง PIVOT
ซึ่งลักษณะนี้จะเป็นรูปแบบ Dynamic ที่ข้อมูลไม่ได้คงที่อาจมีการเพิ่มหรือลดลงได้ ดังนั้นจะต้องทำการ เตรียมข้อมูลสำหรับ PIVOT โดยให้ข้อมูลในตารางที่เป็น cat_id ทุกรายการ เอามาทำให้ให้อยู่ในรูปแบบดังนี้
C01,C02,C03,C04
สามารถทำได้โดยการเขียนคำสั่งดังนี้
DECLARE @colList varchar(MAX)
SELECT @colList = COALESCE(@colList + ',','') + RTRIM(cat_id)
FROM category
SELECT @colList
จะได้ผลลัพธ์ดังภาพ
จากนั้นนำผลลัพธ์ที่เก็บในตัวแปร @colList ไปใช้ในคำสั่ง PIVOT โดยเขียนคำสั่งในรูปของตัวแปร และเรียกประมวลผลผ่านคำสั่ง EXEC ดังนี้
DECLARE @colList varchar(MAX)
SELECT @colList = COALESCE(@colList + ',','') + RTRIM(cat_id) FROM category
DECLARE @SQLQuery NVARCHAR(MAX)
SET @SQLQuery = 'SELECT * FROM
(
SELECT h.inv_date,c.cat_id,SUM(i.amount) as Total FROM inv_dtl i
LEFT JOIN inv_hd h ON i.inv_no = h.inv_no
LEFT JOIN product p ON i.product_id = p.product_id
LEFT JOIN category c ON p.cat_id = c.cat_id
GROUP BY c.cat_id,h.inv_date
) t
PIVOT(
SUM(total)
FOR cat_id IN ('+ @colList +')
) AS pivot_table;';
EXEC(@SQLQuery)
จะได้ผลลัพธ์ตามภาพ
หากไม่ต้องการ คอลัมน์ เป็นรหัส C01 C02 C03 C04 สามารถใช้ชื่อ cat_name มาแทนได้ แต่ต้องระวังเรื่องของความยาว โดยที่ชื่อนั้นไม่ควรยาวมากจนเกินไป และควรใส่ [ ] คลุมระหว่างชื่อด้วยเพื่อป้องกันเรื่องของการเว้นช่องว่างระหว่างคำ
DECLARE @colList varchar(MAX)
SELECT @colList = COALESCE(@colList + ',','') + '[' + RTRIM(cat_name)+ ']' FROM category
DECLARE @SQLQuery NVARCHAR(MAX)
SET @SQLQuery = 'SELECT * FROM
(
SELECT h.inv_date,c.cat_name,SUM(i.amount) as Total FROM inv_dtl i
LEFT JOIN inv_hd h ON i.inv_no = h.inv_no
LEFT JOIN product p ON i.product_id = p.product_id
LEFT JOIN category c ON p.cat_id = c.cat_id
GROUP BY c.cat_name,h.inv_date
) t
PIVOT(
SUM(total)
FOR cat_name IN ('+ @colList +')
) AS pivot_table;';
EXEC(@SQLQuery)
จะได้ผลลัพธ์ ดังภาพ
ขอให้สนุกกับการกลับตาราง
สวัสดี ร่ำรวย ดูหนังกลางแปลง ปิ้งปลาหมึก อร่อย
13 พฤษภาคม 2565
PostgreSQL : กำหนดให้ postgresql เก็บ log คำสั่ง SQL
การกำหนดให้ PostgreSQL เก็บ log คำสั่ง SQL
1. เข้าไปที่แก้ไขไฟล์ postgresql.conf
กรณีใช้ postgresql 14 ถ้ารุ่นอื่นก็เปลี่ยนตัวเลขรุ่นตามต้องการ โดยป้อนคำสั่งผ่าน Terminal
sudo
vim /etc/postgresql/14/main/postgresql.conf
จากนั้น ไปหาและแก้ไขค่าตามนี้
กดปุ่ม i เพื่อเข้าโหมด insert ของ โปรแกรม vim แล้วแก้ไข
log_destination
= 'csvlog'
logging_collector
= on
log_directory = 'pg_log'
log_filename = 'test_postgresql-%Y-%m-%d_%H%M%S.log'
log_statement = 'all'
เมื่อแก้ไขเสร็จให้กดปุ่ม
Esc
เพื่อออกจากโหมดแก้ไข
กด :w บันทึก
กด :q ออก
2. ทำการ รีสตาร์ทเซอร์วิสของ postgresql ใหม่ ด้วยคำสั่ง
sudo systemctl restart postgresql
จากนั้นไป เมื่อมีการใช้คำสั่ง SQL
จัดการกับฐานข้อมูลก็จะถูกเก็บ log ไว้ที่
/var/lib/postgresql/14/main/
ภายใต้โฟลเดอร์ pg_log
เรียกดูไฟล์
sudo ls -l /var/lib/postgresql/14/main/pg_log/
เมื่อพบไฟล์เป้าหมาแล้ว ก็เอาออกมาไว้ที่อื่น เช่น โฟลเดอร์ Desktop
sudo cat /var/lib/postgresql/14/main/pg_log/ชื่อไฟล์log.csv > Desktop/ชื่อไฟล์log.csv
เป็นอันเรียบร้อย
03 พฤษภาคม 2565
PostgreSQL : กำหนด Configuration สำหรับฐานข้อมูล PostgreSQL บน Ubuntu 20.04 ให้สามารถเข้าถึงผ่าน ip address จากภายนอก
การกำหนด Configuration สำหรับฐานข้อมูล PostgreSQL บน Ubuntu 20.04 ให้สามารถเข้าถึงผ่าน ip address จากภายนอก
สำหรับเครื่องที่ใช้ เป็นระบบปฏิบัติการ Windows 10 ดังนั้นเราจำเป็นต้องติดตั้ง Hyper-V ซึ่งเป็น Virtualization ของ Windows เอง ดั้งนั้นของที่มีก็ใช้แบบไม่ต้องไปหาอื่นไกล ส่วนการติดตั้ง Hyper-V และติดตั้ง Ubuntu 20.04 ไม่ขอกล่าวถึง
เปิด Terminal แล้วเรียกใช้คำสั่ง ifconfig ดู ip address แล้วจดไว้เพื่อจะ Connect เข้าถึงข้อมูล
เมื่อติดตั้ง Ubuntu ใน hyper-v เสร็จก็ไปทำการติดตั้ง PostgreSQL ต่อเลยโดยเข้าไปดูตาม Link ด้านล่างได้เลย 555
https://www.cherryservers.com/blog/how-to-install-and-setup-postgresql-server-on-ubuntu-20-04
ทำการเปิด firewall ให้กับ port ที่ต้องการ เช่น 5432 โดยพิมพ์คำสั่ง ดังนี้
sudo ufw allow from any to any port 5432 proto tcp
* สั้ง List รายการเพื่อตรวจสอบว่า port เปิดหรือไม่
sudo lsof -i -P -n | grep LISTEN
ติดตั้งเสร็จ ให้เข้าไปแก้ไข config เพิ่มเติ่มจากเว็บก่อนหน้าที่ให้กำหนดไว้ โดยพิมพ์คำสั่งที่ Terminal
sudo vim /etc/postgresql/14/main/postgresql.conf
แล้วแก้ ตรงส่วนของ listen_addresses = 'local' ให้เป็น
listen_addresses = '*'
จากนั้นไปแก้ไฟล์ pg_hba.conf
sudo vim /etc/postgresql/14/main/pg_hba.conf
แล้วเพิ่มสิทธิ์เข้าไปตามนี้ หรือจะกำหนดเฉพาะไอพีก็ได้ แต่สำหรับตัวอย่างข้างล่างคือเปิดหมด
host all all 0.0.0.0/0 scram-sha-256
host all all ::1/128 trust
host all all 127.0.0.1/32 trust
ทำเสร็จก็ทำการ restart service ด้วยคำสั่ง
systemctl restart postgresql
เสร็จสำหรับ Ubuntu และ PostgreSQL
------------------------------
จากนั้นไปที่เครื่อง Client ที่เราต้องการติดต่อที่ Windows 10
ไปทำการดาวน์โหลด ODBC มาลงที่เครื่อง ที่เว็บ
https://www.postgresql.org/ftp/odbc/versions/msi/
ให้เลือกตัวใหม่ ๆ แล้วเลือก 32 bit หรือ 64 bit ขึ้นอยู่กับโปรแกรมที่เราจะติดต่อว่าเป็น 32 bit หรือ 64 bit ก็ลงตามนั้น
ส่วนการติดต่อก็ผ่าน connection string ประมาณนี้
Driver={PostgreSQL Unicode};Server=172.18.117.166;Port=5432;Database=ชื่อDatabase;Uid=postgres;Pwd=รหัสผ่าน;
ตัวอย่างโปรแกรมที่ใช้เขียนเพื่อติดต่อฐานข้อมูล
cPostgreSQL = [Driver={PostgreSQL Unicode};Server=172.18.117.166;Port=5432;Database=test_erp;Uid=postgres;Pwd=12345555;]
nHandle = SQLSTRINGCONNECT(cPostgreSQL)
IF nHandle > 0
TEXT TO cSQL NOSHOW TEXTMERGE
SELECT * FROM clients
ENDTEXT
nSuccess = SQLEXEC(nHandle,cSQL)
IF nSuccess > 0
** นำข้อมูลมาแสดงข้อมูล
ENDIF
=SQLDISCONNECT(nHandle)
ENDIF










