SELECT CTHD.MaHang, HH.TenHang, CTHD.SoLuong, CTHD.DonGia FROM ChiTietHoaDon as CTHD inner join HoaDon as HD on HD.MaHD=CTHD.MaHD inner join HangHoa as HH on CTHD.MaHang=HH.MaHang WH
Trang 1Đề tài : Xây dựng CSDL quản lý các hoạt động kinh doanh của một siêu thị
Phụ lục của giáo trình : Knowledge Discovery from Database
Giáo viên : Nguyễn Duy Nhất – nhatnd@hcm.fpt.vn
Bài giải
Các yêu cầu tác nghiệp
(1.2) Lập danh sách hàng hóa được mua trong hóa đơn có mã là 1 Danh sách gồm các thuộc tính : mã hàng, tên hàng, số lượng bán, giá bán
SELECT CTHD.MaHang, HH.TenHang, CTHD.SoLuong, CTHD.DonGia
FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD) inner join HangHoa as HH on
CTHD.MaHang=HH.MaHang
WHERE HD.MaHD=1
(1.3) Lập danh sách mục hàng mà khách hàng có mã là 3242 đã mua trong năm
1998 Danh sách gồm các thuộc tính : mã hàng, tên hàng, tổng số lượng đã mua, tổng giá trị
SELECT CTHD.MaHang, HH.TenHang, Sum(CTHD.SoLuong) as TongSoLuong,
Sum(CTHD.SoLuong*CTHD.DonGia) as TongGiaTri FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD) inner join HangHoa as HH on
CTHD.MaHang=HH.MaHang
WHERE (HD.MaKH=3242) and (Year(HD.NgayLap)=1998)
GROUP BY CTHD.MaHang, HH.TenHang
Thử nghiệm câu truy vấn với CSDL Walmart, kết quả trả về gồm 70 dòng có dạng
(1.4) Tính tổng doanh thu của doanh nghiệp (tức tổng số tiền thu về do bán hàng) trong tháng 1 năm 1998
SELECT Sum(HD.TongGiaTri) as DoanhThu
FROM HoaDon as HD
WHERE Month(HD.NgayLap)=1 and Year(HD.NgayLap)=1998
1
Trang 2(1.5) Tính tổng lợi nhuận của doanh nghiệp trong tháng 1 năm 2008
SELECT Sum((CTHD.DonGia - HH.DonGia)*CTHD.SoLuong) as LoiNhuan
FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD) inner join HangHoa as HH on
CTHD.MaHang=HH.MaHang
WHERE Month(HD.NgayLap)=1 and Year(HD.NgayLap)=1998
Kết quả thử nghiệm của các câu truy vấn (1.4) và (1.5) trên CSDL Walmart lần lượt là 325810.58$ và 227601.42$
(1.6) Lập bảng thống kê hàng hóa bán ra trong năm 2008 Bảng gồm các cột (các thuộc tính) : mã hàng, tên hàng, tổng số lượng bán ra, tổng số tiền thu về, tổng lợi nhuận thu được
SELECT CTHD.MaHang, HH.TenHang, Sum(CTHD.SoLuong) as TongSoLuong,
Sum(CTHD.SoLuong*CTHD.DonGia) as TongDoanhThu, Sum((CTHD.DonGia - HH.DonGia)*CTHD.SoLuong) as LoiNhuan FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD) inner join HangHoa as HH on
CTHD.MaHang=HH.MaHang
WHERE Year(HD.NgayLap)=1998
GROUP BY CTHD.MaHang, HH.TenHang
Thử nghiệm câu truy vấn với CSDL Walmart, kết quả trả về có dạng
(1.7) Lập bảng thống kê các loại hàng (nhóm hàng) bán ra trong năm 2008 Bảng gồm các cột (các thuộc tính) : tên loại hàng, tổng số tiền thu về, tổng lợi nhuận thu được
Tương tự (1.6), nhưng phải inner join thêm bảng LoaiHang để có cột tên loại
SELECT LH.MaLoai, LH.TenLoai, Sum(CTHD.SoLuong) as TongSoLuong,
Sum(CTHD.SoLuong*CTHD.DonGia) as TongDoanhThu, Sum((CTHD.DonGia - HH.DonGia)*CTHD.SoLuong) as LoiNhuan
2
Trang 3FROM ( (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD) inner join HangHoa as HH on
CTHD.MaHang=HH.MaHang) inner join LoaiHang as LH on
HH.MaLoai=LH.MaLoai
WHERE Year(HD.NgayLap)=1998
GROUP BY LH.MaLoai, LH.TenLoai
Thử nghiệm câu truy vấn với CSDL Walmart, kết quả trả về có dạng
(1.8) Lập bảng thống kê tình hình tiêu thụ (doanh thu) của các mặt hàng theo từng tháng trong năm 1998 Bảng gồm 15 cột, cột thứ nhất là mã hàng, cột thứ 2 là tên hàng, 12 cột tiếp theo là doanh thu của từng mặt hàng trong từng tháng, cột thứ 15 là doanh thu trung bình
Ta tư duy bài toán theo kiểu tập hợp Bảng thống kê cần lập là một tập hợp nhiều dòng dữ liệu, mỗi dòng biểu diễn tình hình tiêu thụ của một mặt hàng trong từng tháng của năm 1998, nghĩa là mỗi dòng là một bộ số liệu gồm 15 giá trị (ứng với 14 cột) Gọi q là tập hợp cần tìm, q được viết dưới dạng
q = a, b,c ,c , ,c , tb , trong đó a ứng với cột mã hàng, b ứng với tên hàng, và … ứng với doanh thu của 12 tháng, tb ứng với doanh thu trung bình
1
c c12
Nhận xét rằng a phải là một mã hàng trong toàn bộ các mã hàng của bảng HangHoa, hiểu nôm na là, nếu bảng HangHoa có n dòng, nghĩa là doanh nghiệp có
n mặt hàng, thì q cũng phải có n dòng, và mỗi dòng mô tả doanh thu của từng mặt hàng trong 12 tháng Do đó, q được định nghĩa bởi
1 2 12
a HangHoa.MaHang,
b HangHoa : MaHang a TenHang,
q a, b,c ,c , ,c
c ,c , ,c , tb
⎫ , trong đó
3
Trang 4
4
)
(
c =q a, i , với mọi i 1,2, ,12= , và q x, y là câu truy vấn (con) trả về doanh 1( )
thu của mặt hàng có mã là x trong tháng thứ y của năm 1998,
( )
1
tb q x= ′ , là doanh thu trung bình (theo tháng) của mặt hàng có mã là x trong năm 1998
(
1
q x, y) được viết bằng SQL là
SELECT Sum(CTHD.SoLuong*CTHD.DonGia)
FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD)
WHERE (CTHD.MaHang=x) and
(Year(HD.NgayLap)=1998) and (Month(HD.NgayLap)=y)
( )
1
tb q x= ′
Từ đó, ta có dạng SQL của q là
SELECT HH.MaHang, HH.TenHang,
(SELECT Sum(CTHD.SoLuong*CTHD.DonGia) FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD)
WHERE (CTHD.MaHang=HH.MaHang) and
(Year(HD.NgayLap)=1998) and (Month(HD.NgayLap)=1)
) as Thang1,
(SELECT Sum(CTHD.SoLuong*CTHD.DonGia) FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD)
WHERE (CTHD.MaHang=HH.MaHang) and
(Year(HD.NgayLap)=1998) and (Month(HD.NgayLap)=2)
) as Thang2,
…
(SELECT Sum(CTHD.SoLuong*CTHD.DonGia) FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD)
WHERE (CTHD.MaHang=HH.MaHang) and
(Year(HD.NgayLap)=1998) and (Month(HD.NgayLap)=12)
) as Thang12 FROM HangHoa as HH
Thử nghiệm câu truy vấn với CSDL Walmart, kết quả trả về có dạng
Trang 5(1.9) Lập bảng thống kê doanh thu và lợi nhuận của doanh nghiệp trong 12 tháng của năm 1998 Bảng gồm 3 cột : tháng, doanh thu, và lợi nhuận (do đó bảng sẽ có
12 dòng dữ liệu ứng với 12 tháng)
Bảng thống kê cần lập là một tập hợp q có dạng
q = a, b,c , trong đó q có 12 phần tử, tức 12 bộ số liệu có dạng (a, b,c )
Nhận xét rằng a phải mang các giá trị từ 1 đến 12, nghĩa là a thuộc tập hợp
{1,2, ,12 , khi đó b và c sẽ là doanh thu và lợi nhuận của tháng thứ a Do trong }
CSDL hiện tại không có bảng nào chứa tập hợp {1,2, ,12 , nên ta cần tạo một }
bảng dữ liệu mới, ta đặt tên cho bảng này là CacThang, bảng này chỉ cần có một cột, và ta nhập sẵn 12 giá trị là 12 số từ 1 đến 12 cho bảng
Thang
1
2
3
4
5
6
7
8
9
10
11
12
Gọi q x1( ) là doanh thu của doanh nghiệp trong tháng thứ x của năm 1998 q x 1( )
được viết bằng SQL như sau
SELECT Sum(HD.TongGiaTri)
FROM HoaDon as HD
5
Trang 6WHERE (Year(HD.NgayLap)=1998) and (Month(HD.NgayLap)=x)
Gọi q x2( ) là lợi nhuận của doanh nghiệp trong tháng thứ x của năm 1998 q x 2( )
được viết bằng SQL như sau
SELECT Sum((CTHD.DonGia − HH.DonGia)*CTHD.SoLuong)
FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD) inner join HangHoa as HH on
CTHD.MaHang=HH.MaHang
WHERE Month(HD.NgayLap)=x and Year(HD.NgayLap)=1998
Khi đó, dạng SQL của q sẽ là
SELECT CT.Thang,
(SELECT Sum(HD.TongGiaTri) FROM HoaDon as HD
WHERE (Year(HD.NgayLap)=1998) and
(Month(HD.NgayLap)=CT.Thang)
) as DoanhThu,
(SELECT Sum((CTHD.DonGia - HH.DonGia)*CTHD.SoLuong) FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD) inner join HangHoa as HH on
CTHD.MaHang=HH.MaHang
WHERE Month(HD.NgayLap)=CT.Thang and
Year(HD.NgayLap)=1998
) as LoiNhuan FROM CacThang as CT
Thử nghiệm câu truy vấn với CSDL Walmart, kết quả trả về có dạng
(5.4) Lập bảng thống kê khối lượng giao dịch của các khách hàng trong năm 1998 Bảng gồm các cột : mã khách hàng, họ tên khách hàng, ngày sinh, tổng khối lượng
6
Trang 7giao dịch (là tổng số tiền mà khách hàng này đã mua hàng của doanh nghiệp), tổng lợi nhuận (mà doanh nghiệp thu được từ khách hàng này)
Bảng thống kê cần lập là một tập hợp q có dạng
q = a, b,c,d,e , trong đó a là một mã khách hàng, và b, c, d, e là thông tin về khách hàng có mã là
a Nếu a được xác định trong bảng HoaDon thì bảng thống kê lập được sẽ bỏ qua các khách hàng nào không có mua hàng trong năm 1998 Mặt khác, nếu a được xác định trong bảng KhachHang, thì trong bảng thống kê lập được, các dòng ứng với khách hàng nào không có mua hàng trong năm 1998 sẽ không có giá trị (Null), và
ta sẽ đặt giá trị ở đây bằng 0
Trong bài giải sau đây, tác giả xác định a trong bảng KhachHang Khi đó, q được định nghĩa bởi
( ) ( )
1 2
a KhachHang.MaKH,
b KhachHang : MaKH a TenKH,
q a, b,c,d,e c KhachHang : MaKH a NgaySinh,
d q a ,
e q a
,
trong đó, và là các câu truy vấn con tính khối lượng giao dịch và lợi nhuận của khách hàng (có mã là) a
( )
1
q a q a2( )
( )
1
q a được viết bằng SQL là
SELECT Sum(HD.TongGiaTri)
FROM HoaDon as HD
WHERE (HD.MaKH=a) and (Year(HD.NgayLap)=1998)
( )
2
q a được viết bằng SQL là
SELECT Sum((CTHD.DonGia − HH.DonGia)*CTHD.SoLuong)
FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD)
WHERE (HD.MaKH=a) and (Year(HD.NgayLap)=1998)
Khi đó, dạng SQL của q sẽ là
SELECT KH.MaKH, (KH.HoKH + ' ' + KH.TenKH) as HoTen, KH.NgaySinh,
(SELECT Sum(HD.TongGiaTri) FROM HoaDon as HD
WHERE (HD.MaKH=KH.MaKH) and (Year(HD.NgayLap)=1998)
) as KhoiLuongGiaoDich,
(SELECT Sum((CTHD.DonGia - HH.DonGia)*CTHD.SoLuong)
FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD) inner join HangHoa as HH on
CTHD.MaHang=HH.MaHang
WHERE (HD.MaKH=KH.MaKH) and (Year(HD.NgayLap)=1998)
7
Trang 8) as LoiNhuan FROM KhachHang as KH
Để ý rằng trong bảng thống kê trả về từ câu truy vấn trên, giá trị tại các cột KhoiLuongGiaoDich và LoiNhuan sẽ là NULL nếu như khách hàng này không có mua hàng trong năm đang xét (1998)
Thử nghiệm với CSDL Walmart, kết quả có dạng
Để đặt các giá trị NULL là 0, ta có thể sử dụng hàm IsNull (được hỗ trợ bởi SQL Server, hàm tương ứng trong Access là Nz) theo cách
SELECT KH.MaKH, (KH.HoKH + ' ' + KH.TenKH) as HoTen, KH.NgaySinh,
IsNull( (SELECT Sum(HD.TongGiaTri) FROM HoaDon as HD
WHERE (HD.MaKH=KH.MaKH) and (Year(HD.NgayLap)=1998))
, 0) as KhoiLuongGiaoDich,
IsNull( (SELECT Sum((CTHD.DonGia - HH.DonGia)*CTHD.SoLuong)
FROM (ChiTietHoaDon as CTHD inner join HoaDon as HD on
HD.MaHD=CTHD.MaHD) inner join HangHoa as HH on
CTHD.MaHang=HH.MaHang
WHERE (HD.MaKH=KH.MaKH) and (Year(HD.NgayLap)=1998))
, 0) as LoiNhuan FROM KhachHang as KH
Kết quả trở thành
8
Trang 9Các yêu cầu ra quyết định
(1.2) Lập bảng thống kê về mức độ biến động doanh thu của các mặt hàng trong năm 2008 Bảng gồm các cột : mã hàng, tên hàng, độ lệch chuẩn doanh thu Sắp xếp bảng giảm dần theo cột thứ 3
Ở bài 1.8, ta đã lập được bảng thống kê doanh thu của các mặt hàng theo từng tháng Ta lập lại bảng này, nhưng thêm vào cột “Trung bình doanh thu” :
SELECT MaHang, TenHang, ( (IsNull (Thang1,0) + IsNull(Thang2,0) +
IsNull (Thang3,0) + IsNull(Thang4,0) + IsNull(Thang5,0) + IsNull (Thang6,0) + IsNull(Thang7,0) + IsNull(Thang8,0) + IsNull (Thang9,0) + IsNull(Thang10,0) + IsNull(Thang11,0) + IsNull(Thang12,0))/12 ) as TBDoanhThu
FROM (q)
trong đó, q là câu truy vấn ở bài 1.8
Lại từ bảng này, ta lập bảng thống kê theo như đề bài yêu cầu, nghĩa là thêm vào cột “Độ lệch chuẩn doanh thu” :
SELECT MaHang, TenHang, TBDoanhThu,
( (Abs (IsNull(Thang1,0) - TBDoanhThu) + Abs (IsNull(Thang2,0) - TBDoanhThu) + Abs (IsNull(Thang3,0) - TBDoanhThu) + Abs (IsNull(Thang4,0) - TBDoanhThu) + Abs (IsNull(Thang5,0) - TBDoanhThu) + Abs (IsNull(Thang6,0) - TBDoanhThu) + Abs (IsNull(Thang7,0) - TBDoanhThu) + Abs (IsNull(Thang8,0) - TBDoanhThu) + Abs (IsNull(Thang9,0) - TBDoanhThu) + Abs (IsNull(Thang10,0) - TBDoanhThu) + Abs (IsNull(Thang11,0) - TBDoanhThu) +
9
Trang 10Abs (IsNull(Thang12,0) - TBDoanhThu))/12 ) as DoLechChuan FROM (q) as q1 inner join (q′) as q2 on q1.MaHang=q2.MaHang
ORDER BY DoLechChuan Desc
trong đó, q là câu truy vấn ở bài 1.8, q′ là câu truy vấn có cột TBDoanhThu vừa tạo ra ở trên
(1.3) CEO cần kiểm định nhận định về thói quen mua hàng của khách hàng rằng : Nếu khách hàng có mua mã hàng x và mã hàng y cùng lúc thì thường cũng sẽ mua luôn mã hàng z Đánh giá độ tin cậy của nhận định này
Trước hết, cần hiểu rõ khái niệm các mặt hàng “có mua cùng lúc” nghĩa là được mua trong cùng một hóa đơn Để khảo sát độ tin cậy của nhận định này, ta cần lập bảng thống kê về việc các mặt hàng x, y, và z có được mua hay không trong tất cả các hóa đơn mua hàng Bảng thống kê như vậy có dạng :
Mã hóa đơn Mặt hàng X Mặt hàng Y Mặt hàng Z
4 Có Có Có
… … … …
trong đó, mặt hàng x được gọi là có mua trong mã hóa đơn i khi trong bảng
ChiTietHoaDon, có 1 dòng t nào đó, mà t.MaHD = i và t.MaHang = x, và ở đây, ta không quan tâm đến số lượng được mua hay đơn giá bán của x
Để có được bảng thống kê này, ta cần lập bảng thống kê tương tự, có dạng
Mã hóa đơn Mặt hàng X Mặt hàng Y Mặt hàng Z
… … … …
trong đó, các , , lần lượt là số lượng được mua của mặt hàng X, Y, Z trong mã hóa đơn i, các giá trị này bằng 0 nếu không được mua Và từ bảng này, ta sẽ lập được bảng ở trên bằng cách sử dụng phát biểu Case … When để thay các giá trị khác 0 thành “Có” và các giá trị bằng 0 thành “Không”
i
x yi zi
Khi đó, độ tin cậy của nhận định sẽ được tính bằng số dòng (số hóa đơn) có mua X,
Y và Z, chia cho số dòng có mua X, Y Ngược lại, khái niệm nguy cơ sai lầm của
nhận định được tính bằng số dòng có mua X, Y, và không mua Z, chia cho số dòng có mua X, Y Rõ ràng, độ tin cậy = 1 − nguy cơ sai lầm
Bảng thống kê cần lập là một tập hợp có dạng q
10
Trang 11( )
q = a, b,c,d , trong đó a là một mã hóa đơn xác định trong HoaDon.MaHD, b là số lượng được mua của mặt hàng X trong hóa đơn a (b=0 nếu hóa đơn a không có mua X), ý nghĩa tương tự lần lượt cho c và d, ứng với mặt hàng Y và Z
q được định nghĩa bởi
a HoaDon.MaHD,
b ChiTietHoaDon : MaHD a, MaHang x SoLuong b 0 ,
q a, b,c,d
c ChiTietHoaDon : MaHD a, MaHang y SoLuong c 0 ,
d ChiTietHoaDon : MaHD a, MaHang z SoLuong d 0
⎫
∨ =
∨ =
∨ =
q được viết dưới dạng SQL
SELECT HD.MaHD,
IsNull((SELECT CTHD.SoLuong
FROM ChiTietHoaDon as CTHD
WHERE CTHD.MaHD=HD.MaHD and CTHD.MaHang=x),0) as X, IsNull((SELECT CTHD.SoLuong
FROM ChiTietHoaDon as CTHD
WHERE CTHD.MaHD=HD.MaHD and CTHD.MaHang=y),0) as Y, IsNull((SELECT CTHD.SoLuong
FROM ChiTietHoaDon as CTHD
WHERE CTHD.MaHD=HD.MaHD and CTHD.MaHang=z),0) as Z FROM HoaDon as HD
Dạng SQL tính độ tin cậy của nhận định
SELECT (SELECT COUNT(q.MaHD)
WHERE q.X>0 and q.Y>0 and q.Z>0)*100.0/
(SELECT COUNT(q.MaHD)
WHERE q.X>0 and q.Y>0)
trong đó, dấu … đại diện cho câu truy vấn của q vừa xây dựng được ở trên Việc phải nhân tử số cho 100.0, thay vì 100, nhằm đổi kiểu dữ liệu của tử số từ kiểu nguyên thành kiểu thực
Thử nghiệm
Do dữ liệu về hóa đơn trong CSDL Walmart là không lớn (chỉ 34015 hóa đơn), trong khi số mặt hàng lại nhiều (1560 mặt hàng), nên rất khó để tìm được 3 mặt hàng X, Y, và Z đủ tốt để thử nghiệm (có rất ít hóa đơn cùng mua đồng thời 3 mặt hàng X, Y, Z) Ta thực hiện đánh giá một nhận định khác tương tự, với X, Y, Z là các loại hàng, thay vì mặt hàng (trong CSDL Walmart chỉ có 110 loại hàng) Và do các mặt hàng khác nhau, cho dù thuộc cùng một loại, có thể có đơn vị tính của số
11