Hoàng Nhật Phương
Thành viên gắn bó



- Tham gia
- 5/11/15
- Bài viết
- 1,895
- Được thích
- 1,219
Bạn phải miêu tả là làm sao ra được số lượng StockIn và StockOut nha hôn.Xin chào các bạn, OT có một vấn đề sau chưa giải quyết được lên đưa lên đây nhờ tất cả mọi người cùng xem và giúp đỡ.
Cụ thể có 2 bảng dữ liệu 'Inventory' và 'Data':
View attachment 291800
View attachment 291801
Nhờ các bạn giúp đỡ câu lệnh SQL để lấy dữ liệu từ 2 bảng trên trả về kết quả sau:
View attachment 291802
Xin trân trọng cảm ơn
Option Explicit
Sub testCalcInventory()
Dim dic As Object, sheet As Worksheet
Dim inventory As Variant, scan As Variant, result As Variant, Key As Variant
Dim sPart As String, sLot As String, sTockNo As String, sTockNoTo As String, str As String, sTockNoSearch As String
Dim i As Long, j As Long, r As Long, u As Long, k As Long
Dim quantity As Double
Dim c As Integer, style As String
Const sDELIM As String = "|"
Set sheet = ThisWorkbook.ActiveSheet
inventory = sheet.Range("A3:E6").Value
scan = sheet.Range("G3:O29").Value
sTockNoSearch = "*KHO_004*"
If IsArray(inventory) Then r = UBound(inventory, 1)
If IsArray(scan) Then r = r + UBound(scan, 1)
If (r = 0) Then
Exit Sub
End If
If Not IsArray(scan) Then
GoTo Iventory_
End If
Scaner_:
Set dic = CreateObject("Scripting.Dictionary")
c = 8: ReDim result(1 To r * 2, 1 To c)
For i = LBound(scan, 1) To UBound(scan, 1)
style = scan(i, 1)
sPart = scan(i, 2)
sTockNoTo = scan(i, 3)
sTockNo = scan(i, 4)
sLot = scan(i, 7)
quantity = scan(i, 8)
str = Join(Array(sPart, sTockNoTo, sLot), sDELIM)
If Not dic.Exists(str) And (style = "MOV") Then
If UCase(sTockNoTo) Like UCase(sTockNoSearch) Then
k = k + 1
dic.Add str, k
result(k, 1) = k
result(k, 2) = sPart
result(k, 3) = sLot
result(k, 4) = sTockNoTo
End If
End If
Key = Join(Array(sPart, sTockNo, sLot), sDELIM)
If Not dic.Exists(Key) Then
If UCase(sTockNo) Like UCase(sTockNoSearch) Then
k = k + 1
dic.Add Key, k
result(k, 1) = k
result(k, 2) = sPart
result(k, 3) = sLot
result(k, 4) = sTockNo
End If
End If
u = dic.Item(str): r = dic.Item(Key)
Select Case style
Case "IN" 'NHAP KHO
If (r > 0) Then result(r, 6) = result(r, 6) + quantity
If (r > 0) Then result(r, 8) = result(r, 8) + quantity
Case "OUT" 'XUAT KHO
If (r > 0) Then result(r, 7) = result(r, 7) + quantity
If (r > 0) Then result(r, 8) = result(r, 8) - quantity
Case "MOV" 'CHUYEN KHO
If (u > 0) Then result(u, 6) = result(u, 6) + quantity
If (u > 0) Then result(u, 8) = result(u, 8) + quantity
If (r > 0) Then result(r, 7) = result(r, 7) + quantity
If (r > 0) Then result(r, 8) = result(r, 8) - quantity
End Select
Next i
If Not IsArray(inventory) Then
GoTo Result_
End If
Iventory_:
For i = LBound(inventory, 1) To UBound(inventory, 1)
sPart = inventory(i, 1)
sTockNo = inventory(i, 2)
sLot = inventory(i, 3)
quantity = inventory(i, 4)
Key = Join(Array(sPart, sTockNo, sLot), sDELIM)
str = Join(Array(sDELIM, sPart, sTockNo, sLot), sDELIM)
If UCase(sTockNo) Like UCase(sTockNoSearch) Then
If Not dic.Exists(Key) And (quantity > 0) Then
k = k + 1
dic.Add Key, k
result(k, 1) = k
result(k, 2) = sPart
result(k, 3) = sLot
result(k, 4) = sTockNo
result(k, 5) = quantity
result(k, 6) = quantity
Else
If Not dic.Exists(str) And (quantity > 0) Then
dic.Add str, quantity: r = dic.Item(Key)
result(r, 5) = quantity
result(r, 8) = result(r, 5) + result(r, 6) - result(r, 7)
End If
End If
End If
Next i
Result_:
If (k > 0) Then sheet.Range("P13").Resize(k, c).Value = result
End Sub
Dữ liệu và kết quả trong 1 file dùng dic nhanh và dể viết hơn SQL nhiềuXin chào các bạn, OT có một vấn đề sau chưa giải quyết được lên đưa lên đây nhờ tất cả mọi người cùng xem và giúp đỡ.
Cụ thể có 2 bảng dữ liệu 'Inventory' và 'Data':
View attachment 291800
View attachment 291801
Nhờ các bạn giúp đỡ câu lệnh SQL để lấy dữ liệu từ 2 bảng trên trả về kết quả sau:
View attachment 291802
Xin trân trọng cảm ơn
Con chào bác Hiếu,Dữ liệu và kết quả trong 1 file dùng dic nhanh và dể viết hơn SQL nhiều
Gặp ca phức tạp bạn nên dùng nhiều query, trường hợp nầy cần 2 query lấy dữ liệu từ 2 bảng và 1 query lấy kết quả từ 2 query trên, SQL được đơn giản hóaCon chào bác Hiếu,
Dạ con mô tả vậy thôi bác, dữ liệu là lấy trực tiếp từ SQL ra đó bác. Con muốn thay vì lấy về sau đó mới xử lý thì sẽ xử lý luôn bằng câu lệnh SQL bác ạ. Với lại con cũng muốn tìm hiểu về câu lệnh SQL với trường hợp này ạ, vì trong thực tế con gặp nhiều.
Cảm ơn bác đã góp ý ạ.
Dạ dùng nhiều query cũng được bác con cũng thường làm như vậy, khi kết nối đến CSDL thì sẽ cho chạy hết một lượt ạ.Gặp ca phức tạp bạn nên dùng nhiều query, trường hợp nầy cần 2 query lấy dữ liệu từ 2 bảng và 1 query lấy kết quả từ 2 query trên, SQL được đơn giản hóa
Nhờ bác và mọi người chỉ giúp ạ.1 query lấy kết quả từ 2 query trên
Trường hợp này ta có thể không cần dùng khoá như bạn đề cập.Nếu nói về SQL:
- Khóa liên kết = Item & LotNo & StockNo
- Select If (StockType = "Out" Or StockType = "Mov") and StockNo = "Kho-004" then Quantity else 0 As StockOut
thêm If StockType = "In" and StockNo = "Kho-004" Or Or StockType = "Mov" and StockNoTo = "Kho-004" then Quantity else 0 As Stockin
- Where Item = "MH002"
Đại khái vậy
Con cảm ơn bác VetMini nhiều, một gợi ý rất cơ bản và logic con sẽ thử xem con có làm được không ạ.Table1 là Master File. Chứa dữ liệu căn bản của Inventory (hàng hóa)
Table2 là Transaction File. Chứa các phát sinh cho Inventory (xuất nhập,...)
Đối với mọi CSDL, phân biệt loại bảng là điều quan trọng, cần phải nhớ rõ.
Bài này cần khá nhiều bảng dữ liệu tạm.
1. Lọc dữ liệu theo mã inventory
(Select * From Table2 Where Item = 'MH002') As Table22.
2. Lọc theo IN
(Select *, StockNo As PosNo, Quantity As QtyIN, 0 As QtyOUT From Table22 Where StockType = 'IN')
Lọc theo OUT
(Select *, StockNo As PosNo, 0 As QtyIN, Quantity As QtyOUT From Table22 Where StockType = 'OUT')
Lọc theo MOV (in)
(Select *, StockNoTo As PosNo, Quantity As QtyIN, 0 As QtyOUT From Table22 Where StockType = 'MOV')
Lọc theo MOV (out)
(Select *, StockNo As PosNo, 0 As QtyIN, Quantity As QtyOUT From Table22 Where StockType = 'MOV')
UNION ALL 4 cái lọc trên, bạn sẽ được một bảng transaction (phát sinh) mới cho Item chọn lựa và IN/OUT đã phân biệt rõ.
Công việc kế tiếp là GROUP chúng lại theo ITEM, POSNO, LOTNO; và tổng các Qty's
Công việc bây giờ của bạn chỉ là JOIN nó (Item và LotNo, POSNO với STOCKNO) với Table1 để lấy thêm dữ liệu (tồn đầu)
Đó là cách làm căn bản để lọc lại Transactions với nhiều kiểu (IN/OUT/MOV)
Nó rắc rối bởi vì cách thiết kế hai bảng Master và Transaction của bạn không đạt chuẩn.
Cách làm gọn hơn là theo ý của bài #227, các Transactions chỉ lọc một lần và dùng lô gic IF-THEN-ELSE để phân biệt cách đối xử khi gặp các loại StockType khác nhau (lưu ý là bài của bạn dùng từ Stocktype là sai, tên đúng thì phải là TransType)
Tuy nhiên, bài #227 trên chỉ gợi ý. SQL của Access không hỗ trợ lệnh If-Then-Else hay Case cho nên bạn phải dùng IIF hoặc Switch.
Lưu ý là Table2 của bạn thiết kế rất kém cho nên việc xử lý loại "MOV" rất phức tạp. Làm cách nào để đổi một MOV thành 1 OUT (dễ) cộng 1 IN (rất khó).
Trường hợp này ta nên thoải mái và thả lỏng nó ra chút nha bạn.Table1 là Master File. Chứa dữ liệu căn bản của Inventory (hàng hóa)
Table2 là Transaction File. Chứa các phát sinh cho Inventory (xuất nhập,...)
Đối với mọi CSDL, phân biệt loại bảng là điều quan trọng, cần phải nhớ rõ.
Bài này cần khá nhiều bảng dữ liệu tạm.
1. Lọc dữ liệu theo mã inventory
(Select * From Table2 Where Item = 'MH002') As Table22.
2. Lọc theo IN
(Select *, StockNo As PosNo, Quantity As QtyIN, 0 As QtyOUT From Table22 Where StockType = 'IN')
Lọc theo OUT
(Select *, StockNo As PosNo, 0 As QtyIN, Quantity As QtyOUT From Table22 Where StockType = 'OUT')
Lọc theo MOV (in)
(Select *, StockNoTo As PosNo, Quantity As QtyIN, 0 As QtyOUT From Table22 Where StockType = 'MOV')
Lọc theo MOV (out)
(Select *, StockNo As PosNo, 0 As QtyIN, Quantity As QtyOUT From Table22 Where StockType = 'MOV')
UNION ALL 4 cái lọc trên, bạn sẽ được một bảng transaction (phát sinh) mới cho Item chọn lựa và IN/OUT đã phân biệt rõ.
Công việc kế tiếp là GROUP chúng lại theo ITEM, POSNO, LOTNO; và tổng các Qty's
Công việc bây giờ của bạn chỉ là JOIN nó (Item và LotNo, POSNO với STOCKNO) với Table1 để lấy thêm dữ liệu (tồn đầu)
Đó là cách làm căn bản để lọc lại Transactions với nhiều kiểu (IN/OUT/MOV)
Nó rắc rối bởi vì cách thiết kế hai bảng Master và Transaction của bạn không đạt chuẩn.
Cách làm gọn hơn là theo ý của bài #227, các Transactions chỉ lọc một lần và dùng lô gic IF-THEN-ELSE để phân biệt cách đối xử khi gặp các loại StockType khác nhau (lưu ý là bài của bạn dùng từ Stocktype là sai, tên đúng thì phải là TransType)
Tuy nhiên, bài #227 trên chỉ gợi ý. SQL của Access không hỗ trợ lệnh If-Then-Else hay Case cho nên bạn phải dùng IIF hoặc Switch.
Lưu ý là Table2 của bạn thiết kế rất kém cho nên việc xử lý loại "MOV" rất phức tạp. Làm cách nào để đổi một MOV thành 1 OUT (dễ) cộng 1 IN (rất khó).
Dạ được ạ, chỉ cần ra kết quả đúng là đủ rồi ạ.Trường hợp này ta nên thoải mái và thả lỏng nó ra chút nha bạn.
@Hoàng Nhật Phương:
Kết quả sẽ đúng yêu cầu nhưng thứ tự không được như ý bạn. Bạn có chịu không?
View attachment 291823
Với đoạn truy vấn sau sẽ ra kết quả. Tuy nhiên sẽ còn cách khác tối ưu hơn.Dạ được ạ, chỉ cần ra kết quả đúng là đủ rồi ạ.
Còn thư tự theo kết quả mẫu không phải vấn đề,nhờ bạn giúp đỡ ạ.
Cảm ơn bạn nhiều.
SELECT ITEM,
LOTNO,
STOCKNO,
Sum(OPENINGSTOCK),
Sum(STOCKIN),
Sum(STOCKOUT),
Sum(OPENINGSTOCK) + Sum(STOCKIN) - Sum(STOCKOUT)
FROM (SELECT ITEM,
LOTNO,
STOCKNO,
0 AS OpeningStock,
Iif(STOCKTYPE = 'IN', QUANTITY, 0) AS StockIn,
Iif(STOCKTYPE = 'IN', 0, QUANTITY) AS StockOut
FROM [NXT$G2:O29]
UNION ALL
SELECT ITEM,
LOTNO,
STOCKNOTO,
0,
QUANTITY,
0
FROM [NXT$G2:O29]
WHERE STOCKTYPE LIKE 'MOV'
UNION ALL
SELECT ITEM,
LOTNO,
STOCKNO,
QUANTITY,
0,
0
FROM [NXT$A2:E6])
WHERE STOCKNO LIKE 'KHO_004'
GROUP BY ITEM,
LOTNO,
STOCKNO
Tôi không muốn nói chuyện về cái này. Thoải mái hya khong chỉ là chủ quan của mỗi người.Trường hợp này ta nên thoải mái và thả lỏng nó ra chút nha bạn.
Nếu đã tới kết quả rồi thì chỉ cần sort theo 12 ký tự đầu của LotNo (descending) và các ký tự còn lại (ascending)@Hoàng Nhật Phương:
Kết quả sẽ đúng yêu cầu nhưng thứ tự không được như ý bạn. Bạn có chịu không?
...
Nếu dùng câu "Suy nghĩ thoáng hơn" thì hợp lý hơn. Như tôi đã nói, thứ tự sẽ không như mong muốn, Bạn hướng dẫn như trên chưa đạt 100% yêu cầu. Dĩ nhiên ta có cách sắp xếp theo thứ tự nhưng phức tạp không đáng.Tôi không muốn nói chuyện về cái này. Thoải mái hya khong chỉ là chủ quan của mỗi người.
Nếu đã tới kết quả rồi thì chỉ cần sort theo 12 ký tự đầu của LotNo (descending) và các ký tự còn lại (ascending)
Bạn chưa thấy dữ liệu gốc bao giờ.Trường hợp này ta có thể không cần dùng khoá như bạn đề cập.
Đúng vậy, tôi chỉ gợi ý. Đã biết SQL, hỏi trong chủ đề SQL, thì đáng lẽ chỉ gợi ý vậy thôi là làm được.Tuy nhiên, bài #227 trên chỉ gợi ý.
Vậy cái Group by nó không có ý nghĩa gì trong trường hợp này sao bạn? Kho thì đã Group theo mã kho rồi. Có nhiều kho mà có cùng mã hàng thì đâu ảnh hưởng gì phải không nào.Bạn chưa thấy dữ liệu gốc bao giờ.
Bảng 1: Dữ liệu tồn kho bao giờ cũng có: Nhiều kho, nhiều mặt hàng, mỗi kho nhiều mặt hàng, mỗi mặt hàng nhiều kho, mỗi mặt hàng nhiều lot nhập về.
Bảng 2: dữ liệu phát sinh (hàng ngày) cũng nhiều dạng như vậy và nhân lên nhiều ngày.
Không có trường khóa tạo quan hệ là chết chắc.
Mấu chốt CSDL bắt buộc phải vậy chứ phát sinh nhập xuất lot này, kho này mà lấy tồn đầu kho khác, lot khác là báo cáo vứt đi ngay.
Đúng vậy, tôi chỉ gợi ý. Đã biết SQL, hỏi trong chủ đề SQL, thì đáng lẽ chỉ gợi ý vậy thôi là làm được.
Group by theo tôi chỉ là biện pháp chữa cháy. Mà thôi, tôi nói thừa rồi. Thừa với người giỏi như bạn, còn đối với dữ liệu khác, người khác thì ... chuyện gì xảy ra nếu có 1 mặt hàng tồn kho không nhập xuất, hoặc 1 mặt hàng không tồn kho nhưng có nhập xuất?Vậy cái Group by nó không có ý nghĩa gì trong trường hợp này sao bạn? Kho thì đã Group theo mã kho rồi. Có nhiều kho mà có cùng mã hàng thì đâu ảnh hưởng gì phải không nào.
Hi hi!!! Có ràng buộc dữ liệu là lúc nhập liệu á bạn, ở đây là xử lý dữ liệu thô đã có sẵn. Đúng không bạn?Group by theo tôi chỉ là biện pháp chữa cháy. Mà thôi, tôi nói thừa rồi. Thừa với người giỏi như bạn, còn đối với dữ liệu khác, người khác thì ... chuyện gì xảy ra nếu có 1 mặt hàng tồn kho không nhập xuất, hoặc 1 mặt hàng không tồn kho nhưng có nhập xuất?