Truy vấn trong SQL? (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

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
Xin chào các bạn.
OT chạy câu lệnh sau:
Mã:
SELECT
    sc.name + '.' + ta.name TableName,
    SUM(pa.rows) RowCnt
FROM
    sys.tables ta
INNER Join
    sys.partitions pa
ON
    pa.OBJECT_ID = ta.OBJECT_ID
INNER Join
    sys.Schemas sc
ON
    ta.schema_id = sc.schema_id
WHERE
    ta.is_ms_shipped = 0
AND
    pa.index_id IN (1,0)
Group BY
    sc.name,
    ta.name
Order BY
    Sum (pa.Rows)
DESC
Kết quả trả về tên bảng và số dòng của bảng và sắp xếp giảm giần theo cột số dòng trong bảng.

Mã:
SELECT
    TABLE_NAME,
COLUMN_NAME
FROM
     INFORMATION_SCHEMA.Columns
Kết quả trả về tên bảng và tên các cột trong bảng.

Xin hỏi có câu lệnh nào để trả về 3 dữ liệu: tên bảng, tên cột trong bảng, số dòng trong cột?
 
"Số dòng trong cột" là như thê nào nhỉ?
thường thì mình nói về số dòng của bảng, vì ô mà không có dữ liệu (NULL) thì vẫn là một ô.
 
Xin chào các bạn.
OT chạy câu lệnh sau:
Mã:
SELECT
    sc.name + '.' + ta.name TableName,
    SUM(pa.rows) RowCnt
FROM
    sys.tables ta
INNER Join
    sys.partitions pa
ON
    pa.OBJECT_ID = ta.OBJECT_ID
INNER Join
    sys.Schemas sc
ON
    ta.schema_id = sc.schema_id
WHERE
    ta.is_ms_shipped = 0
AND
    pa.index_id IN (1,0)
Group BY
    sc.name,
    ta.name
Order BY
    Sum (pa.Rows)
DESC
Kết quả trả về tên bảng và số dòng của bảng và sắp xếp giảm giần theo cột số dòng trong bảng.

Mã:
SELECT
    TABLE_NAME,
COLUMN_NAME
FROM
     INFORMATION_SCHEMA.Columns
Kết quả trả về tên bảng và tên các cột trong bảng.

Xin hỏi có câu lệnh nào để trả về 3 dữ liệu: tên bảng, tên cột trong bảng, số dòng trong cột?
Câu lệnh tra cứu tên các database trong SQL là:
select name from sys.databases

Câu lệnh tra cứu tên các bảng trong 1 database là:
select table_name from information_schema.tables

Câu lệnh tra cứu tên các cột trong 1 table là:
select column_name from INFORMATION_SCHEMA.COLUMNS where table_name = 'chungtu'
ở đây đang Ví dụ tên bảng là chung tu (table_name='chungtu')
 
"Số dòng trong cột" là như thê nào nhỉ?
thường thì mình nói về số dòng của bảng, vì ô mà không có dữ liệu (NULL) thì vẫn là một ô.

Xin chào anh Bình,

Đúng rồi thường là sẽ nói về số dòng của bảng bảng cột nào nhiều dòng nhất thì sẽ lấy số dòng của cột đó.
Ở đây OT muốn lấy dữ liệu của các ô có dữ liệu của các cột trong bảng như minh họa ảnh kèm bên dưới ạ.

Mục đích cũng chỉ là hỏi để xem có câu lệnh này không?
Và OT muốn sử dụng câu lệnh này để kiểm tra thông tin thôi ạ.
Mong anh và mọi người xem giúp ạ.


Untitled.jpg
 

Theo như hình của bạn, thông tin vừa lấy từ các table hệ thống vừa truy vấn số dòng NOT NULL trong từng table riêng nên tôi nghĩ là không có cách join các table để lấy thông tin trực tiếp như bạn yêu cầu mà phải dùng cách đi vòng: tạo table tạm lưu thông tin (Tên bảng, Tên Cột, Ô có dữ liệu) rồi mới cập nhật dữ liệu vào table này. Các bạn chuyên về SQL Server có cách khác thì hỗ trợ giùm nhé.

Cách tôi làm như sau: Vì bạn chủ yếu muốn thống kế nên tôi làm kiểu thủ công trực tiếp trong SQL Server nhé.

1. Tạo table tạm:

Mã:
USE NORTHWIND --Đổi tên Database của bạn.
GO
CREATE TABLE myDBInfo (
    TblName VARCHAR(30),
    ColName VARCHAR(30),
    NumRow INT
);


2. Insert dữ liệu từ INFORMATION_SCHEMA.COLUMNS vào table tạm:

Mã:
USE NORTHWIND
GO
INSERT INTO myDBInfo SELECT TABLE_NAME, COLUMN_NAME,0 FROM INFORMATION_SCHEMA.COLUMNS


3. Tạo các stored proc. (SP) để thực thi việc cập nhật dữ liệu: tạo 2 SP

- SP: UpdatemyDBInfoTbl

Mã:
USE [NORTHWIND]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[UpdatemyDBInfoTbl]
@TName nvarchar(30),
@CName nvarchar(30)
AS
BEGIN
SET NOCOUNT ON;
Declare @sql nvarchar(300);
    Set @sql='UPDATE myDBInfo SET NumRow = (SELECT count(*) FROM ' +  @TName + ' WHERE ' + @CName + ' Is Not Null) WHERE myDBInfo.TblName =''' + @TName + ''' AND myDBInfo.ColName =''' + @CName + ''''
    EXEC sp_executesql @sql
    --print @sql
END

- SP: GetNumRowNotNull

Mã:
USE [NORTHWIND]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GetNumRowNotNull]

AS
BEGIN
declare @TName varchar(30)
Declare @CName varchar(30)
declare cur CURSOR LOCAL for
    select TblName, ColName from myDBInfo

open cur

fetch next from cur into @TName, @CName


while @@FETCH_STATUS = 0 BEGIN
--print @TName
--print  @CName
    --Chạy Store Proc. cho từng dòng
 
    exec dbo.UpdatemyDBInfoTbl @TName, @CName

    fetch next from cur into @TName, @CName

END

close cur
deallocate cur
END


==> Xong. Bây giờ chạy lệnh thực thi SP trên.

Mã:
Exec sp_executesql GetNumRowNotNull

Và xem kết quả:

Mã:
select * from mydbinfo


220786


- Trong Excel bạn dùng ADO Command để gửi lệnh yêu cầu SQL Server thực thi cái stored proc. "GetNumRowNotNull".
- Sau đó bạn dùng ADO Recordset để lấy dữ liệu từ table "myDbInfo" về Excel sheet như cách bạn đang làm.
- Một cái quan trọng để tránh lỗi cho cái SP trong SQL server là đặt tên Table, tên Field không có khoảng trắng nhé.
 
Lần chỉnh sửa cuối:
Theo như hình của bạn, thông tin vừa lấy từ các table hệ thống vừa truy vấn số dòng NOT NULL trong từng table riêng nên tôi nghĩ là không có cách join các table để lấy thông tin trực tiếp như bạn yêu cầu mà phải dùng cách đi vòng: tạo table tạm lưu thông tin (Tên bảng, Tên Cột, Ô có dữ liệu) rồi mới cập nhật dữ liệu vào table này. Các bạn chuyên về SQL Server có cách khác thì hỗ trợ giùm nhé.

Cách tôi làm như sau: Vì bạn chủ yếu muốn thống kế nên tôi làm kiểu thủ công trực tiếp trong SQL Server nhé.

1. Tạo table tạm:

Mã:
USE NORTHWIND --Đổi tên Database của bạn.
GO
CREATE TABLE myDBInfo (
    TblName VARCHAR(30),
    ColName VARCHAR(30),
    NumRow INT
);


2. Insert dữ liệu từ INFORMATION_SCHEMA.COLUMNS vào table tạm:

Mã:
USE NORTHWIND
GO
INSERT INTO myDBInfo SELECT TABLE_NAME, COLUMN_NAME,0 FROM INFORMATION_SCHEMA.COLUMNS


3. Tạo các stored proc. (SP) để thực thi việc cập nhật dữ liệu: tạo 2 SP

- SP: UpdatemyDBInfoTbl

Mã:
USE [NORTHWIND]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[UpdatemyDBInfoTbl]
@TName nvarchar(30),
@CName nvarchar(30)
AS
BEGIN
SET NOCOUNT ON;
Declare @sql nvarchar(300);
    Set @sql='UPDATE myDBInfo SET NumRow = (SELECT count(*) FROM ' +  @TName + ' WHERE ' + @CName + ' Is Not Null) WHERE myDBInfo.TblName =''' + @TName + ''' AND myDBInfo.ColName =''' + @CName + ''''
    EXEC sp_executesql @sql
    --print @sql
END

- SP: GetNumRowNotNull

Mã:
USE [NORTHWIND]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GetNumRowNotNull]

AS
BEGIN
declare @TName varchar(30)
Declare @CName varchar(30)
declare cur CURSOR LOCAL for
    select TblName, ColName from myDBInfo

open cur

fetch next from cur into @TName, @CName


while @@FETCH_STATUS = 0 BEGIN
--print @TName
--print  @CName
    --Chạy Store Proc. cho từng dòng

    exec dbo.UpdatemyDBInfoTbl @TName, @CName

    fetch next from cur into @TName, @CName

END

close cur
deallocate cur
END


==> Xong. Bây giờ chạy lệnh thực thi SP trên.

Mã:
Exec sp_executesql GetNumRowNotNull

Và xem kết quả:

Mã:
select * from mydbinfo


View attachment 220786


- Trong Excel bạn dùng ADO Command để gửi lệnh yêu cầu SQL Server thực thi cái stored proc. "GetNumRowNotNull".
- Sau đó bạn dùng ADO Recordset để lấy dữ liệu từ table "myDbInfo" về Excel sheet như cách bạn đang làm.
- Một cái quan trọng để tránh lỗi cho cái SP trong SQL server là đặt tên Table, tên Field không có khoảng trắng nhé.

Xin chào ongke0711,
Cảm ơn anh rất nhiều OT đã hiểu cách làm ạ.
Như vậy sau lần đầu (bảng "myDbInfo" đã được thiết lập) thì mỗi lần kiểm tra phải xóa cái bảng "myDbInfo" đi và lặp lại các thao tác trên phải không ạ?
Nếu vậy có câu lệnh nào cập nhật lại thông tin vào bảng "myDbInfo"không? theo OT hiểu các lần thứ 2 trở đi chỉ cần thao tác từ bước:
Là được phải không ạ?
Nếu không phải như vậy thì phiền anh có thể viết thêm câu lệnh xóa bảng "myDbInfo" với điều kiện nếu nó đang tồn tại trong Database ạ.
OT hiện giờ chưa có điều kiện môi trường để test nên xác nhận ạ :D
 
Như vậy sau lần đầu (bảng "myDbInfo" đã được thiết lập) thì mỗi lần kiểm tra phải xóa cái bảng "myDbInfo" đi và lặp lại các thao tác trên phải không ạ?
Nếu vậy có câu lệnh nào cập nhật lại thông tin vào bảng "myDbInfo"không? theo OT hiểu các lần thứ 2 trở đi chỉ cần thao tác từ bước:

Em chạy code sau để cập nhật lại cái SP "GetNumRowNotNull".
Sau này chỉ cần chạy cái SP trên, nó sẽ xoá nội dung table myDBInfo (không xoá table), cập nhật lại tên table, column sau đó cập nhật số dòng.

Mã:
USE [NORTHWIND]
GO
/****** Object:  StoredProcedure [dbo].[GetNumRowNotNull]    Script Date: 07/08/2019 7:25:45 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetNumRowNotNull]

AS
BEGIN

DELETE FROM myDBInfo
INSERT INTO myDBInfo SELECT TABLE_NAME, COLUMN_NAME, 0 FROM INFORMATION_SCHEMA.COLUMNS

declare @TName varchar(30)
Declare @CName varchar(30)
declare cur CURSOR LOCAL for
    select TblName, ColName from myDBInfo

open cur

fetch next from cur into @TName, @CName


while @@FETCH_STATUS = 0 BEGIN
--print @TName
--print  @CName
    --Chạy Store Proc. cho từng dòng
  
    exec dbo.UpdatemyDBInfoTbl @TName, @CName

    fetch next from cur into @TName, @CName

END

close cur
deallocate cur
END
 
Xin chào các bạn.
OT chạy câu lệnh sau:
Mã:
SELECT
    sc.name + '.' + ta.name TableName,
    SUM(pa.rows) RowCnt
FROM
    sys.tables ta
INNER Join
    sys.partitions pa
ON
    pa.OBJECT_ID = ta.OBJECT_ID
INNER Join
    sys.Schemas sc
ON
    ta.schema_id = sc.schema_id
WHERE
    ta.is_ms_shipped = 0
AND
    pa.index_id IN (1,0)
Group BY
    sc.name,
    ta.name
Order BY
    Sum (pa.Rows)
DESC
Kết quả trả về tên bảng và số dòng của bảng và sắp xếp giảm giần theo cột số dòng trong bảng.

Mã:
SELECT
    TABLE_NAME,
COLUMN_NAME
FROM
     INFORMATION_SCHEMA.Columns
Kết quả trả về tên bảng và tên các cột trong bảng.

Xin hỏi có câu lệnh nào để trả về 3 dữ liệu: tên bảng, tên cột trong bảng, số dòng trong cột?
Cái này là tư duy của range, bảng trong excel-vba nên bỏ đi
Khi đã quan niệm là theo Cơ sở dữ liệu - thì đối tượng quan tâm chính nên là Data (dữ liệu) và đối tượng xử lý là table, field, recordset, ... và Relationship...
 
Theo như mình biết thì ngay cả MS SQL không thể truy vấn đơn thuần để ra kết quả như trên mà phải tìm phương án đi vòng như của ongkeo711.
 
Cái này là tư duy của range, bảng trong excel-vba nên bỏ đi
Khi đã quan niệm là theo Cơ sở dữ liệu - thì đối tượng quan tâm chính nên là Data (dữ liệu) và đối tượng xử lý là table, field, recordset, ... và Relationship...
Schema là metadata.
Xáo trộn giữa metadata và data là công việc của data manager hoặc desinger.
Đây là công việc cao cấp. Thường thì sau khi hệ thống phần mềm đưa vào hoạt động cỡ 1 năm (hay 6 tháng, tuỳ theo độ lớn) thì data designer sẽ bắt đầu lập thống kê dữ liệu để hiệu chỉnh lại metadata.
Như đã nói, làm công việc này là hàng cao cấp cho nên ông nội tôi cũng không dám xía vào. Công việc không phải chỉ viết 1 cái sp rồi đọc kết quả. Từ khoá ở đây là "hiệu chỉnh".
 
Schema là metadata.
Xáo trộn giữa metadata và data là công việc của data manager hoặc desinger.
Đây là công việc cao cấp. Thường thì sau khi hệ thống phần mềm đưa vào hoạt động cỡ 1 năm (hay 6 tháng, tuỳ theo độ lớn) thì data designer sẽ bắt đầu lập thống kê dữ liệu để hiệu chỉnh lại metadata.
Như đã nói, làm công việc này là hàng cao cấp cho nên ông nội tôi cũng không dám xía vào. Công việc không phải chỉ viết 1 cái sp rồi đọc kết quả. Từ khoá ở đây là "hiệu chỉnh".
Cao cấp mà phải giải thích nôm na mới khó và tôi cũng chịu
Nên phải nói rằng cái chính cần quan tâm thì không, lại đi quan tâm cái quá chính
 
Lần chỉnh sửa cuối:
Xin chào các bạn,
Trong SQL-DB , Oanh Thơ(OT) đang sử dụng câu lệnh sau để lấy dữ liệu từ bảng SODER:
Mã:
select CODE,CDATE,QTY from SODER
Kết quả dữ liệu xuất ra như Sheet1.
Giờ OT mong muốn lấy dữ liệu như dữ liệu trong sheet2 với điều kiện >="01/09/2019" và < "01/10/2019"
Thì câu lệnh truy vấn sẽ như thế nào ạ?
 
Xin chào các bạn,
Trong SQL-DB , Oanh Thơ(OT) đang sử dụng câu lệnh sau để lấy dữ liệu từ bảng SODER:
Mã:
select CODE,CDATE,QTY from SODER
Kết quả dữ liệu xuất ra như Sheet1.
Giờ OT mong muốn lấy dữ liệu như dữ liệu trong sheet2 với điều kiện >="01/09/2019" và < "01/10/2019"
Thì câu lệnh truy vấn sẽ như thế nào ạ?
Xin lỗi OT quên đính kèm file
 

File đính kèm

Xin chào các bạn,
Trong SQL-DB , Oanh Thơ(OT) đang sử dụng câu lệnh sau để lấy dữ liệu từ bảng SODER:
Mã:
select CODE,CDATE,QTY from SODER
Kết quả dữ liệu xuất ra như Sheet1.
Giờ OT mong muốn lấy dữ liệu như dữ liệu trong sheet2 với điều kiện >="01/09/2019" và < "01/10/2019"
Thì câu lệnh truy vấn sẽ như thế nào ạ?

- Dùng hàm DateSerial() nhé bạn.
- Không được dùng các từ khoá của hệ thống làm tên Fieldm tên biến. "CDate"

SELECT Code, Ngay, Qty, DateSerial(Left([Ngay],4),Mid([Ngay],5,2),Right([Ngay],2)) As NgayChuyen FROM SORDER WHERE [NgayChuyen] Between #" & txtTuNgay & "# AND #" & txtDenNgay & "#"
 
- Dùng hàm DateSerial() nhé bạn.
- Không được dùng các từ khoá của hệ thống làm tên Fieldm tên biến. "CDate"

SELECT Code, Ngay, Qty, DateSerial(Left([Ngay],4),Mid([Ngay],5,2),Right([Ngay],2)) As NgayChuyen FROM SORDER WHERE [NgayChuyen] Between #" & txtTuNgay & "# AND #" & txtDenNgay & "#"

Xin chào ongke0711
Cảm ơn anh đã quan tâm và giúp đỡ.
OT truy vấn câu lệnh sau:
Mã:
SELECT Code, CDATE, Qty, DateSerial(Left([CDATE],4),Mid([CDATE],5,2),Right([CDATE],2)) As NgayChuyen FROM SORDER  WHERE [NgayChuyen] between '2019-09-01' and '2019-10-01'

Thì báo lỗi sau:
Msg 195, Level 15, State 10, Line 1
'Mid' is not a recognized built-in function name.

Nhờ anh xem giúp ạ.
Bảng SORDER này cột của nó đặt là "CDATE" ạ
 
Oh. Em xài SQL Server 2008 à? Em thay thế hàm Mid bằng hàm SubString đi.
 
muốn truy vấn chuẩn thì đầu tiên phải biết datatype của các cột là gì nhé.

t-sql thì: select ... cast([cdate] as date) as xx where fieldate between '2019-07-01' and '2019-07-31'
 
Lần chỉnh sửa cuối:
A! Được rồi ạ, OT xin trân trọng cảm ơn sự quan tâm giúp đỡ của mọi người ạ.
CDATE chắc là định dạng Date nên OT thử câu lệnh:
Mã:
..WHERE CDATE between '2019-09-01' and '2019-10-01'
OK rồi ạ
 
A! Được rồi ạ, OT xin trân trọng cảm ơn sự quan tâm giúp đỡ của mọi người ạ.
CDATE chắc là định dạng Date nên OT thử câu lệnh:
Mã:
..WHERE CDATE between '2019-09-01' and '2019-10-01'
OK rồi ạ
kiểm tra mới chắc chắn đc nhé, vì trong nhiều trường sẽ xảy ra trường hợp tự ép kiểu nhé. mình dùng điện thoại nên không xem cụ thể thế nào nhưng qua phỏng đoán code trên thì cột của bạn là yyyymmdd và nó là varchar chứ không là date, date trong ms sql là yyyy-mm-dd, trong th của bạn là ép kiểu rồi.

bạn chạy câu lệnh là biết date trong ms sql fortmat chuẩn ntn: select getdate()
 
Nếu CDATE là kiểu date thì phải bảo đảm nó là Short Date, không phải DateTime.
Bởi vì >= '20190701' And < '20190801'
khác với Between '20190701' and '20190731'
Trường hợp 1 sẽ kể luôn những '20190731 23:59:59 99.99999'. Trường hợp 2 cứ 1 giây là loại rồi.
 
Dạ OT sử dụng SQL-2017 anh ạ, lại phát sinh lỗi này anh ạ:
Mã:
Msg 195, Level 15, State 10, Line 1
'DateSerial' is not a recognized built-in function name.

:) Lỗi do anh lẫn lộn giữa hàm bên VBA và SQL Server, râu ông nọ cắm cằm bà kia.
Em phải đổi NVarchar thành DateTime thì mới thực hiện các phép so sánh + - ngày tháng chính xác.
Dùng hàm DateFromParts() tương tự hàm DateSerial() trong VBA. Ngắn gọn là dùng CAST hoặc CONVERT.

Convert(nvarchar, CDATE, 23)

SELECT CODE, CDATE, QTY FROM SORDER WHERE Convert(nvarchar,CDATE,23) between '2019-09-01' And '2019-10-01'
 
Lần chỉnh sửa cuối:
Xin cảm ơn mọi người đã giúp đỡ,
OT kiểm tra trong CSDL thì nó như thế này ạ, không biết câu lệnh sẽ xử lý theo cách nào là chuẩn ạ.

222186

222187


Nhưng dù sao nhờ có sự giúp đỡ của mọi người nên vấn đề của OT cũng đã được giải quyết ạ.
 
Xin cảm ơn mọi người đã giúp đỡ,
OT kiểm tra trong CSDL thì nó như thế này ạ, không biết câu lệnh sẽ xử lý theo cách nào là chuẩn ạ.

View attachment 222186

View attachment 222187


Nhưng dù sao nhờ có sự giúp đỡ của mọi người nên vấn đề của OT cũng đã được giải quyết ạ.
bạn sử dụng hàm cast thôi cast(cdate as date) between x and y. còn k bạn k cần cast thì nó tự ép kiểu cho bạn
 
Kiếm cái thằng thiết kế CSDL mà hỏi nó số 1 ở sau có nghĩa là gì.
Điển hình đối với một số phần mềm kế toán, người ta thêm mọt ký hiệu sau ngày tháng để chỉ quý. Đối với một số nước trên thế giới tháng 7+8+9 là quý 1.

Troing hiện tại thì với yêu câù của bạn, cứ lấy 6 ký tự đầu là tháng, 8 ký tự là ngày.
Dạng YYYYMMDD đã được chuẩn để có thể so sánh theo kiểu chuỗi, không cần phải cast. Chỉ khi nào cần cộng trừ ngày tháng mới phải cast.
 
... Xin phép được xóa nội dung tại bài #30 này (OT hiểu rồi)
 
Lần chỉnh sửa cuối:
Xin chào mọi người,
Nhờ mọi người giúp đỡ OT câu lệnh Select để lấy dữ liệu từ 4 bảng sau đó tạo ra vùng dữ liệu như bảng bên dưới với ạ.

222251
 

File đính kèm

Trường [Ngày tháng] không có sao bạn OT?
Nếu dữ liệu tồn kho, đơn hàng mấy năm thì máy chạy mệt à.
 
Xin chào Anh ongke0711
Dạ tất nhiên là có Anh ạ, OT chỉ ví dụ vậy để biết cách vận dụng ạ :D
Nhờ anh xem giúp ạ.

Tôi hỏi kỹ để tránh việc đưa một câu lênh T-SQL mà kết quả của nó không có ý nghĩa gì hết, rồi em áp dụng cũng không được.
Cái mấu chốt nằm ở cái table STOCK của em. Nó là tồn kho ngay tại thời điểm chạy query hay tồn đầu kỳ (từng tháng).
- Nếu là tồn đầu kỳ thì đưa vào truy vấn số lượng bán (tôi suy ra theo cái tên SOrder - Sales Order) tồn kho không chính xác vì còn phải + thêm nhập TK tính tới ngày xuất bán -> lúc đó mới có ý nghĩa: đối chiếu với tồn kho thời điểm (Quantity On Hand) trước khi xuất bán.
- Nếu đó là table tồn kho thời điểm xét thì không có gì để nói. :)
- Có trường hợp "MH001" bán cho các khách hàng khác không? vd KH002, KH005... Khi nhìn table KHACHHANG tôi lại nghĩ nó giống Nhà Cung Cấp và cái SORDER trở thành table Mua hàng (PURCHASE ORDER) hơn. Khi đó lại sẽ phát sinh các vấn đề khác về tổ chức lưu thông tin (hoặc do em cung cấp thông tin table liên quan quá ít nên không nhìn thấy tổ chức tổng thể của CSDL).
Nếu cái bảng kết quả em muốn là tồn kho và số lượng đặt hàng của từng nhà cung cấp thì table STOCK thiếu thông tin Mã NCC của từng Mã hàng tồn kho.
Nếu nói mỗi Mã Hàng chỉ có 1 NCC cố định nên gán Mã Hang đi theo NCC rồi như table KHACHANG, truy vấn từ Mã hàng sẽ ra mã NCC thì cũng sai vì chỉ nhìn ngắn hạn. Sau này có đổi mua của NCC khác thì theo dõi như thế nào? tồn kho NCC cũng, tồn kho NCC mới...

Tại tôi muốn hiểu rõ chút về quan hệ giữa các Table, các field như thế nào và thông tin từ em cung cấp cũng không nhiều nên hỏi tùm lum là vậy rồi mới ra được câu lệnh truy vấn. Chứ để ra kết quả như trên thì không có gì phức tạp.
 
Lần chỉnh sửa cuối:
Tôi hỏi kỹ để tránh việc đưa một câu lênh T-SQL mà kết quả của nó không có ý nghĩa gì hết, rồi em áp dụng cũng không được.
Cái mấu chốt nằm ở cái table STOCK của em. Nó là tồn kho ngay tại thời điểm chạy query hay tồn đầu kỳ (từng tháng).
- Nếu là tồn đầu kỳ thì đưa vào truy vấn số lượng bán (tôi suy ra theo cái tên SOrder - Sales Order) tồn kho không chính xác vì còn phải + thêm nhập TK tính tới ngày xuất bán -> lúc đó mới có ý nghĩa: đối chiếu với tồn kho thời điểm (Quantity On Hand) trước khi xuất bán.
- Nếu đó là table tồn kho thời điểm xét thì không có gì để nói. :)
- Có trường hợp "MH001" bán cho các khách hàng khác không? vd KH002, KH005... Khi nhìn table KHACHHANG tôi lại nghĩ nó giống Nhà Cung Cấp và cái SORDER trở thành table Mua hàng (PURCHASE ORDER) hơn. Khi đó lại sẽ phát sinh các vấn đề khác về tổ chức lưu thông tin (hoặc do em cung cấp thông tin table liên quan quá ít nên không nhìn thấy tổ chức tổng thể của CSDL).
Nếu cái bảng kết quả em muốn là tồn kho và số lượng đặt hàng của từng nhà cung cấp thì table STOCK thiếu thông tin Mã NCC của từng Mã hàng tồn kho.
Nếu nói mỗi Mã Hàng chỉ có 1 NCC cố định nên gán Mã Hang đi theo NCC rồi như table KHACHANG, truy vấn từ Mã hàng sẽ ra mã NCC thì cũng sai vì chỉ nhìn ngắn hạn. Sau này có đổi mua của NCC khác thì theo dõi như thế nào? tồn kho NCC cũng, tồn kho NCC mới...

Tại tôi muốn hiểu rõ chút về quan hệ giữa các Table, các field như thế nào và thông tin từ em cung cấp cũng không nhiều nên hỏi tùm lum là vậy rồi mới ra được câu lệnh truy vấn. Chứ để ra kết quả như trên thì không có gì phức tạp.

Xin chào ongke0711,
Cảm ơn anh đã quan tâm & giúp đỡ ạ.
Các vấn đề anh hỏi liên quan đến tính toán OT chưa nghĩ đến, có lẽ nó thuộc phần nâng cao hơn một chút ạ, các vấn đề này OT sẽ tạo thêm ví dụ khác ạ , lúc đó có gì anh lại chỉ dẫn thêm ạ.
Còn thực sự OT đang tìm hiểu về câu lệnh select Join từ nhiều bảng (tương tự hàm tìm kiếm trong Excel) thôi ạ nên đưa ví dụ minh họa đơn giản như vậy.
Cảm ơn anh nhiều ạ.
 
Quản lý hàng hoá (Inventory Control) là công việc lớn. Hệ thống quản lý nếu có đầy đủ thông tin xuất nhập tồn thì rất phức tạp. Và vì mõi cơ quan có quy trình làm việc khác nhau cho nên rất khó thiết lập.
Để thiết lập csdl, người ta có hai chọn lựa:
1. chọn một hệ thống có sẵn, và tương đối gần với quy trình của mình. Và chỉnh lại chính quy trình của mình cho phù hợp.
2. mướn chuyên viên theo dõi quy trình của mình và thiết kế mọt hệ thống thật phù hợp.

Đấy là tôi nói chỉ Inventory Control. Nếu phải theo dõi đơn đặt hàng (Purchase Orders/Sales Orders) thì còn lớn hơn nhiều.

Theo như cái bảng yêu cầu ở bài #31 thì bạn cần xem stock có đủ để cung cấp cho đơn đặt hàng hay không. Công việc này có thể thuộc về khâu quản kho nhưng cũng có thể thuộc về khâu bán hàng. Tôi doán ở đây bạn muốn nói khâu kho - nếu khâu bán hàng thì phải thêm phần ngày giao hàng và phân bổ ưu tiên khách hàng/đơn hàng khi không đủ hàng, rất rắc rối.

Nói về lý thuyết 1 chút. Theo lý thuyết CSDL LH thì bạn chỉ cần 1 bảng phát sinh nhập xuất hàng. Tồn kho ở mọi thời điểm sẽ là tổng các phát sinh kể từ ngày đầu tiên cho đến thời điểm ấy. Trên thực tế, người quản lý CSDL ai cũng biết rằng dạng CSDL LH là một con khủng long. Tình trạng lý tưởng là tối thiểu chuẩn bậc 3 (3rd order normalisation) lắm khi ảnh hưởng đến tốc độ truy vấn.

Vì vậy, những CSDL có liên quan đến khái niệm tồn đầu/tồn cuối thường được thiết kế theo dạng phân từng phần (Partitioned). Điển hình như csdl của bạn, ngừoi ta có thể thiết kế bảng Stock theo năm. Tồn đầu kỳ có nghĩa là tồn đầu năm. Và tồn tại thời điểm có nghĩa là tồn đầu năm cộng/trừ các phát sinh trong năm.

Tuy nhiên, nhìn theo hình ở bài #31 thì có lẽ bảng của bạng theo dạng tồn tại chỗ. Mỗi phát sinh sẽ cộng/trừ thẳng vào trường "tồn" trong bảng. Cái báo cáo mà bạn muốn trong bảng thứ 5 là loại báo cáo dữ liệu cấp thời (impromptu). Nói cách khác, nó chỉ có giá trị đúng vào thời điểm truy vấn, và nó giả sử rằng mọi đơn đặt hàng bán và mua đều nằm trong khoảng thời gian tính toán - cái giả sử này là điều mà tác giả bài #34 muón bạn phải khẳng định.

Tóm lại, nếu:
1. bảng 5 trong hình là báo cáo xem tình trạng tồn kho có đủ cung ứng đơn đặt hàng, VÀ
2. trường SoLuong2 chứa tồn kho đến thời điểm hiện tại, VÀ
3. trường SoLuong1 chứa số lượng nằm trong đơn đặt hàng (chưa giao)
Hội đủ 3 điều kiện trên thì câu truy vấn khá đơn giản.
 
Nếu chỉ đơn giản là tham khảo thì em thử câu lệnh này:

- Theo như hình của em, anh lấy trường [MASP] từ table DSSANPHAM.

Mã:
SELECT DSSANPHAM.MASP, DSSANPHAM.TENSP, KHACHHANG.MKH, STOCK.SOLUONG2, SORDER.SOLUONG1
FROM (KHACHHANG RIGHT JOIN (DSSANPHAM LEFT JOIN SORDER ON DSSANPHAM.MASP = SORDER.MSP) ON KHACHHANG.MASP = DSSANPHAM.MASP) LEFT JOIN STOCK ON DSSANPHAM.MASP = STOCK.MSP



- Nếu để đối chiếu tồn kho với table xuất hàng (SORDER) thì trường mã SP phải lấy từ table SORDER, khi đó câu lệnh phải đổi lại là:

Mã:
SELECT SORDER.MSP, DSSANPHAM.TENSP, KHACHHANG.MKH, STOCK.SOLUONG2, SORDER.SOLUONG1
FROM KHACHHANG INNER JOIN (DSSANPHAM INNER JOIN (SORDER LEFT JOIN STOCK ON SORDER.MSP = STOCK.MSP) ON DSSANPHAM.MASP = SORDER.MSP) ON KHACHHANG.MASP = SORDER.MSP
 
Lần chỉnh sửa cuối:
Dạ OT xin cảm ơn Bác VetMini và Anh ongke0711 đã góp ý và chỉ dẫn ạ.

Liên quan đến truy vấn dạng dữ liệu kiểu nhập,xuất, tồn từ SQL... OT sẽ gửi dữ liệu cụ thể nên sau.. đây cũng là một vấn đề OT đang rất quan tâm mà chưa giải quyết và đề cập đến được ạ.
Rất mong khi đó được Bác và Anh cùng mọi người giúp đỡ ạ.
 
Tôi có nói rõ là nó rất rắc rối. Không thể tư vấn theo kiểu diễn đàn được. Bắt buộc phải ăn dầm nằm dề tại kho mà quan sát từng công việc.
Việc cốt kiếc này nọ là chuyện tay trái của tôi cho nên tôi có thể sẵn sàng làm.
Nhưng thiết kế CSDL cho Inventory Control thì tôi không sẵn sàng. Không phải tôi giấu nghề, nhưng tư vấn mà không biết rõ quy trình và không chủ động được quy trình thì tôi từ chối.
Tôi không hề mắc cở khi có ngừoi nói "thằng VM viết code rác rưởi này à?".
Nhưng tôi không chấp nhận một ngày nào đó, có người nói "thằng VM thiết kế cái CSDL rác rưởi này à?"

(*) chủ động quy trình có nghĩa là nếu tôi nói "làm như thế này mới đúng" thì cơ quan phải làm như thế; không có chuyện "nhưng mà..."
 
Tôi có nói rõ là nó rất rắc rối. Không thể tư vấn theo kiểu diễn đàn được. Bắt buộc phải ăn dầm nằm dề tại kho mà quan sát từng công việc.
Việc cốt kiếc này nọ là chuyện tay trái của tôi cho nên tôi có thể sẵn sàng làm.
Nhưng thiết kế CSDL cho Inventory Control thì tôi không sẵn sàng. Không phải tôi giấu nghề, nhưng tư vấn mà không biết rõ quy trình và không chủ động được quy trình thì tôi từ chối.
Tôi không hề mắc cở khi có ngừoi nói "thằng VM viết code rác rưởi này à?".
Nhưng tôi không chấp nhận một ngày nào đó, có người nói "thằng VM thiết kế cái CSDL rác rưởi này à?"

(*) chủ động quy trình có nghĩa là nếu tôi nói "làm như thế này mới đúng" thì cơ quan phải làm như thế; không có chuyện "nhưng mà..."
Con cảm ơn Bác VetMini nhiều ạ.
Thực ra CSDL, khi cài đặt phần mềm đã có tại Server rồi Bác ạ. Nên khâu thiết kế là không cần nữa Bác ạ.
Nhưng phần mềm mới chỉ quản lý nhật ký xuất, nhập hàng ngày và tồn theo tại thời điểm hiện tại, tồn kho đầu kỳ. Không thể lấy được tồn kho theo từng thời điểm.

Ví dụ hiện đang là thời điểm ngày 5/8 trong hệ thống csdl chỉ quản lý tồn kho đầu kỳ sau kiểm kê hết ngày 31/7 và tồn ở thời điểm hiện tại là ở ngày 5/8 là số lượng cụ thể bao nhiêu.

Nhưng khi đứng ở ngày 5/8 nếu con muốn biết dữ liệu tồn kho từ 1/7 đến ngày 25/7 của mã hàng A là bao nhiêu thì hệ thống không có.
Do đó con muốn sử dụng câu truy vấn trong sql để làm việc này.
Về dữ liệu cụ thể, con sẽ cung cấp sau ạ, vì hiện con cũng đang chưa hiểu dữ liệu ở các bảng trong sql liên quan như thêa nào để gửi lên ạ.
OT cảm ơn Bác VetMini và Anh ongke0711 đã quan tâm và giúp đỡ ạ.
 
Nhưng phần mềm mới chỉ quản lý nhật ký xuất, nhập hàng ngày và tồn theo tại thời điểm hiện tại, tồn kho đầu kỳ. Không thể lấy được tồn kho theo từng thời điểm.

Ví dụ hiện đang là thời điểm ngày 5/8 trong hệ thống csdl chỉ quản lý tồn kho đầu kỳ sau kiểm kê hết ngày 31/7 và tồn ở thời điểm hiện tại là ở ngày 5/8 là số lượng cụ thể bao nhiêu.

Nhưng khi đứng ở ngày 5/8 nếu con muốn biết dữ liệu tồn kho từ 1/7 đến ngày 25/7 của mã hàng A là bao nhiêu thì hệ thống không có.

Nếu CSDL đã có kết chuyển tồn cuối kỳ (hoặc tồn đầu) theo tháng và tồn tại thời điểm rồi thì chắc chắn là đã có giải thuật tính tồn kho theo khoảng thời gian cần truy vấn rồi. Chắc là bạn chưa biết nó nằm trong cái stored proc. nào để gọi ra thôi.
 
Con cảm ơn Bác VetMini nhiều ạ.
Thực ra CSDL, khi cài đặt phần mềm đã có tại Server rồi Bác ạ. Nên khâu thiết kế là không cần nữa Bác ạ.
Nhưng phần mềm mới chỉ quản lý nhật ký xuất, nhập hàng ngày và tồn theo tại thời điểm hiện tại, tồn kho đầu kỳ. Không thể lấy được tồn kho theo từng thời điểm.

Ví dụ hiện đang là thời điểm ngày 5/8 trong hệ thống csdl chỉ quản lý tồn kho đầu kỳ sau kiểm kê hết ngày 31/7 và tồn ở thời điểm hiện tại là ở ngày 5/8 là số lượng cụ thể bao nhiêu.

Nhưng khi đứng ở ngày 5/8 nếu con muốn biết dữ liệu tồn kho từ 1/7 đến ngày 25/7 của mã hàng A là bao nhiêu thì hệ thống không có.
Do đó con muốn sử dụng câu truy vấn trong sql để làm việc này.
Về dữ liệu cụ thể, con sẽ cung cấp sau ạ, vì hiện con cũng đang chưa hiểu dữ liệu ở các bảng trong sql liên quan như thêa nào để gửi lên ạ.
OT cảm ơn Bác VetMini và Anh ongke0711 đã quan tâm và giúp đỡ ạ.
Tôi khuyên bạn nên tìm tài liệu của người thiết kế hệ thống QL hàng mà đọc.
Một phần mềm cài đặt luôn luôn có hồ sơ và tài liệu về thiết kế (design documents, user's guide,...). Nếu không có thì cơ quan bạn mướn nhằm thằng cà chớn cài đặt rồi.
Hệ thống tôi thiết kế ngoài những tài liệu kể trên còn cả tài liệu thẩm định về hiệu quả sau 3, 6, và 12 tháng.
Hầu hết những stored procedures liên quan đến cập nhật dữ liệu cũng đều có hồ sơ ghi rõ chức năng.

Chỉ riêng cái câu tôi tô đỏ ở trên cũng đủ cho thấy bạn không hiểu nhiệm vụ của QL hàng tồn kho rồi.
Hàng tồn kho là con số cho biết tình trạng của hàng ở một thời điểm (ngay tại ngày), không thể là con số ở một khoảng thời gian (từ ngày đến ngày). Trong khoảng thời gian thì bạn chỉ có thể lấy những con số thống kê, ví dụ từ ngày xxx đến ngày yyy thì trung bình tồn kho là 123, cao nhất là 456, thấp nhất là 0, có 3 lần thiếu hàng, vân vân...
Và cả nhu cầu lẫn khả năng cung cấp con số thống kê đã được thẩm định từ lúc thiết kế.
 
Chỉ riêng cái câu tôi tô đỏ ở trên cũng đủ cho thấy bạn không hiểu nhiệm vụ của QL hàng tồn kho rồi.
Hàng tồn kho là con số cho biết tình trạng của hàng ở một thời điểm (ngay tại ngày), không thể là con số ở một khoảng thời gian (từ ngày đến ngày). Trong khoảng thời gian thì bạn chỉ có thể lấy những con số thống kê, ví dụ từ ngày xxx đến ngày yyy thì trung bình tồn kho là 123, cao nhất là 456, thấp nhất là 0, có 3 lần thiếu hàng, vân vân...
Và cả nhu cầu lẫn khả năng cung cấp con số thống kê đã được thẩm định từ lúc thiết kế.

Chắc là ý em OT muốn lấy báo cáo Nhập - Xuất - Tồn trong một khoảng thời gian nhưng không diễn giải đúng đó anh VetMini. Tồn kho ở từng thời điểm nhâp xuất.
 
Tôi khuyên bạn nên tìm tài liệu của người thiết kế hệ thống QL hàng mà đọc.
Một phần mềm cài đặt luôn luôn có hồ sơ và tài liệu về thiết kế (design documents, user's guide,...). Nếu không có thì cơ quan bạn mướn nhằm thằng cà chớn cài đặt rồi.
Hệ thống tôi thiết kế ngoài những tài liệu kể trên còn cả tài liệu thẩm định về hiệu quả sau 3, 6, và 12 tháng.
Hầu hết những stored procedures liên quan đến cập nhật dữ liệu cũng đều có hồ sơ ghi rõ chức năng.

Chỉ riêng cái câu tôi tô đỏ ở trên cũng đủ cho thấy bạn không hiểu nhiệm vụ của QL hàng tồn kho rồi.
Hàng tồn kho là con số cho biết tình trạng của hàng ở một thời điểm (ngay tại ngày), không thể là con số ở một khoảng thời gian (từ ngày đến ngày). Trong khoảng thời gian thì bạn chỉ có thể lấy những con số thống kê, ví dụ từ ngày xxx đến ngày yyy thì trung bình tồn kho là 123, cao nhất là 456, thấp nhất là 0, có 3 lần thiếu hàng, vân vân...
Và cả nhu cầu lẫn khả năng cung cấp con số thống kê đã được thẩm định từ lúc thiết kế.
Xin chào Bác VetMini,
Đúng rồi ạ, hiện con đang chưa hiểu được về nhiệm vụ quản lý hàng tồn kho.
Còn về tài liệu cho phần mềm của công ty con gần như không có thông tin gì ạ. Trong giao diện phần mềm thì không thể lấy dữ liệu xuất nhập tồn theo từng thời điểm trong quá khứ được, trong khi đó kế toán thi thoảng vẫn cần báo báo để phụ vụ thanh tra thuê ạ.

Chắc là ý em OT muốn lấy báo cáo Nhập - Xuất - Tồn trong một khoảng thời gian nhưng không diễn giải đúng đó anh VetMini. Tồn kho ở từng thời điểm nhâp xuất.
Xin chào Anh ongke0711,
Đúng đúng rồi Anh ạ, OT cần báo cáo này. Nhưng do phần mềm không có chức năng tạo báo cáo xuất nhập tồn trong khoảng thời điểm bất kỳ trong quá khứ nên OT mới cần truy vấn trong SQL ạ.

Không biết câu lệnh truy vấn dựa vào nhật,ký xuất nhập ở các thời điểm liệu có tính ra được tồn kho được hay không ạ?
Nhưng trước hết OT cần tìm hiểu thêm về các bảng dữ liệu trong CSLD có những gì đã ạ. Rồi nhờ Bác/Anh và mọi người xem giúp ạ.
Híc,anh IT cho động vào máy chủ mà OT thấy ghê quá ạ,nghịch linh sợ nó hư dữ liệu thì mệt lắm ạ.
Nên OT chỉ dám sử dụng câu lệnh Select trong SQL thôi ạ.

Cảm ơn Bác và Anh đã góp ý.
 
Pm mua hay đặt hàng viết riêng vậy bạn OverTime ? Của VN hay nước ngoài?
Nếu của VN thì hầu như đặt hàng họ sửa chữa, thêm bớt được. Cứ liên hệ họ và dắt Bác theo. Nhớ phải có thời gian, điều kiện bảo hành rõ ràng nhen, không thì lại tốn Bác đấy
Còn không được thì dắt Bác qua cho Ông Kẹ. Mấy vụ database này trên GPE nó sợ bạn Ông Kẹ lắm đấy :)
 
Có những ngôn từ hơi nóng về chính trị một chút.
Người "anh hùng" có thể ỷ mình bất khả xâm phạm nhưng kẻ "trượng phu" phải biết suy nghĩ cho hoàn cảnh của người khác.
 
Còn không được thì dắt Bác qua cho Ông Kẹ. Mấy vụ database này trên GPE nó sợ bạn Ông Kẹ lắm đấy :)

Bác CuAnh nói quá rồi... CSDL tôi còn chưa sạch nước cản nữa mà. Chẳng qua là có xem qua vài cái CSDL về bán hàng, nhân sự nên góp vài ý kiến thôi. :-)
 
Tính tồn kho thời điểm đã qua thì không khó lắm.
Nếu là SQL Server (chính bản, không phải Express) thì người thiết kế thường có cái view cho biết tồn kho ở từng đầu kỳ. Ví dụ tôi ở tài khoá 2019 thì tôi sẽ có 12 cái views của 12 tháng 2018, và 8 cái views cho tháng 1-8 2019.
Việc tính tồn kho từng thời điểm chỉ là truy vấn cái view đúng đầu kỳ và cộng/trừ đi những phát sinh cho đến thời điểm cần tính.
Nếu không có những cái views này thì:
1. Bảo người thiết kế viết sp để thiết lập chúng, HOẶC
2. Chịu khó mò cái tồn kho gần nhất. Và làm tương tự như trên

Tính tồn kho dự toán tương lai thì mới khó. Vì phải tính tình trạng từng hợp đồng đã ký, hoặc dự định ký nhưng chưa xuất kho.
(có một số hệ thống xuất kho rồi vẫn tính là hàng còn trong tay, bên kia nhận rồi mới tính là hàng không còn của mình)
 
Không biết câu lệnh truy vấn dựa vào nhật,ký xuất nhập ở các thời điểm liệu có tính ra được tồn kho được hay không ạ?
Nhưng trước hết OT cần tìm hiểu thêm về các bảng dữ liệu trong CSLD có những gì đã ạ. Rồi nhờ Bác/Anh và mọi người xem giúp ạ.
Híc,anh IT cho động vào máy chủ mà OT thấy ghê quá ạ,nghịch linh sợ nó hư dữ liệu thì mệt lắm ạ.
Nên OT chỉ dám sử dụng câu lệnh Select trong SQL thôi ạ.

Có nhật ký Xuất - Nhập + Tồn kho đầu kỳ (hoặc cuối kỳ tuỳ theo CSDL của em) là truy xuất ra được tồn kho luỹ tiến theo từng nghiệp vụ Xuất Nhập. Đừng kêu tính đơn giá bình quân gia quyền hay báo cáo NXT theo FIFO, LIFO là được...hehe.. :)
 
Có nhật ký Xuất - Nhập + Tồn kho đầu kỳ (hoặc cuối kỳ tuỳ theo CSDL của em) là truy xuất ra được tồn kho luỹ tiến theo từng nghiệp vụ Xuất Nhập. Đừng kêu tính đơn giá bình quân gia quyền hay báo cáo NXT theo FIFO, LIFO là được...hehe.. :)

Cảm ơn Bác VetMini , Anh ongke0711 đã luôn quan tâm & giúp đỡ OT ạ.
OT cũng chưa nghiên cứu được dữ liệu trong CSDL ở các bảng liên quan với nhau như thế nào nên chưa đưa dữ liệu lên được.
Bác và Anh có tài liệu hoặc biết link nào tiếng Việt về CSDL/ liên quan cụ thể đến quản lý kho không ạ gửi cho OT thử "nghịch" với được không ạ.
Híc anh IT cấm không cho OT sử dụng câu lệnh nào ngoài câu lệnh SELECT trong DB thật ạ, còn muốn làm gì thì anh ý cũng tạo ra một DB bản sao cho nghịch mà OT cũng chưa biết nên bắt đầu từ đâu ạ.
Khổ có trường, có nơi thực hành nhưng không có Thầy ạ T_T
 
Cảm ơn Bác VetMini , Anh ongke0711 đã luôn quan tâm & giúp đỡ OT ạ.
OT cũng chưa nghiên cứu được dữ liệu trong CSDL ở các bảng liên quan với nhau như thế nào nên chưa đưa dữ liệu lên được.
Bác và Anh có tài liệu hoặc biết link nào tiếng Việt về CSDL/ liên quan cụ thể đến quản lý kho không ạ gửi cho OT thử "nghịch" với được không ạ.
Híc anh IT cấm không cho OT sử dụng câu lệnh nào ngoài câu lệnh SELECT trong DB thật ạ, còn muốn làm gì thì anh ý cũng tạo ra một DB bản sao cho nghịch mà OT cũng chưa biết nên bắt đầu từ đâu ạ.
Khổ có trường, có nơi thực hành nhưng không có Thầy ạ T_T
Bắt đầu từ đâu thì không biết máy ở nhà của bạn đã cài đặt SQL server chưa? Bạn nói anh IT đó sao lưu cho bạn một cái DB riêng, sau đó chạy riêng trên máy bạn và test, cái này mình hay làm cho công ty mình, do công ty mình chỉ cho phép truy cập vào database qua các máy trên cty, nên mình thường hay sao lưu 1 bản rồi về nhà chạy để test.
 
Xin chào các bạn.
Nhờ các bạn giúp đỡ OT trường hợp sau với ạ.

Trong màn hình giao diện phần mềm quản lý kho sử dụng câu lệnh:
Mã:
select cast(0 as decimal(29,3))  as TONKHO 
...

Cột TONKHO có số liệu tồn kho.
Nhưng trong màn hình SQL.Dabase OT chạy câu lệnh đó vào thì kết quả là 0.

Xin hỏi phải sửa trong SQL.Dabase như thế nào để có dữ liệu giống như giao diện phần mềm ạ
 
Trong màn hình giao diện phần mềm quản lý kho sử dụng câu lệnh:
Mã:
select cast(0 as decimal(29,3))  as TONKHO
...

Cột TONKHO có số liệu tồn kho.
Nhưng trong màn hình SQL.Dabase OT chạy câu lệnh đó vào thì kết quả là 0.

Xin hỏi phải sửa trong SQL.Dabase như thế nào để có dữ liệu giống như giao diện phần mềm ạ

Thay số 0 thành tên field tưng ứng cần chuyển đổi.
Cast (Tên field As Decimal.....)
 
Xin chào các bạn.
Nhờ các bạn giúp đỡ OT trường hợp sau với ạ.

Trong màn hình giao diện phần mềm quản lý kho sử dụng câu lệnh:
Mã:
select cast(0 as decimal(29,3))  as TONKHO
...

Cột TONKHO có số liệu tồn kho.
Nhưng trong màn hình SQL.Dabase OT chạy câu lệnh đó vào thì kết quả là 0.

Xin hỏi phải sửa trong SQL.Dabase như thế nào để có dữ liệu giống như giao diện phần mềm ạ
Cách tốt nhất hỏi nhà sx phần mềm (hoặc đọc được code của họ), vì ai biết sau khi nhập chuỗi Sql đó vào trong chương trình xử lý gì tiếp (chẳng hạn thay số 0 như suy đoan của ongke trên , hoặc là khác thì sao)
 
Cảm ơn ongke0711 đã giúp đỡ
Anh có thể chỉ cho OT dựa vào đâu để biết Tên field này không ạ?

Đúng như bạn ppc0312 đã đề cập, thường câu lệnh này chỉ là trung gian trong một truy vấn gì đó như Union query, stored proc... chứ câu lệnh này không phải để em thay tên field. Anh gợi ý cách thay tên field để em hiểu về cú pháp và để truy vấn ra số tồn kho.
Muốn hiểu hơn thì phải có toàn bộ đoạn code trên mới phán đoán được.
 
Nhìn vô choáng luôn. Union query gộp nhiều Recordset lại với nhau, những recordset không có các cột như ZAIK...sẽ phải tạo thêm cột đó với gía trị mặc định =0 để các phép tính toán liên quan đến field này không có giá trị null.
Còn nhìn vô mấy câu lệnh T-SQL này với tên field đặc thù như vậy thì làm sao người ngoài cuộc hiểu được nội dung field đó là gì, câu lệnh đó chạy kết quả ra cái gì mà giúp bạn được.
Tính tồn kho thì ứng với mỗi kiểu thiết kế CSDL khác nhau sẽ có những cách phối hợp xử lý các bảng biểu khác nhau để truy vấn ra tồn kho. Nói chung chung thì khó xử lý lắm nhé.


Xin chào ongke0711,
Cảm ơn Anh đã giúp đỡ, OT đã xử lý được vấn đề bằng cách sử dụng vba để tính toán sau khi lấy được các dữ liệu liên quan.
--------
Một vấn đề khác nhờ Anh và mọi người xem giúp ạ, trong câu lệnh sau:
Mã:
....
strSQL = “SELECT * FROM tblODER WHERE MAHANG LIKE ’KH%'”
rs.Open strSQL, conn
Dim ws As Worksheet
Set ws = Application.Sheets.Add
ws.Range(“A1”).CopyFromRecordset rs
Msgbox rs.Fields.Count
....
rs.Fields.Count sẽ trả về số cột của rs
Vậy làm thế nào để kiểm tra được số dòng trả về của rs (không dùng phương pháp kiểm tra trên bảng tính excel sau khi ghi xuống bảng tính)
 
Lần chỉnh sửa cuối:
Xin chào ongke0711,
Cảm ơn Anh đã giúp đỡ, OT đã xử lý được vấn đề bằng cách sử dụng vba để tính toán sau khi lấy được các dữ liệu liên quan.
--------
Một vấn đề khác nhờ Anh và mọi người xem giúp ạ, trong câu lệnh sau:
Mã:
....
strSQL = “SELECT * FROM tblODER WHERE MAHANG LIKE ’KH%'”
rs.Open strSQL, conn
Dim ws As Worksheet
Set ws = Application.Sheets.Add
ws.Range(“A1”).CopyFromRecordset rs
Msgbox rs.Fields.Count
....
rs.Fields.Count sẽ trả về số cột của rs
Vậy làm thế nào để kiểm tra được số dòng trả về của rs (không dùng phương pháp kiểm tra trên bảng tính excel sau khi ghi xuống bảng tính)
sử dụng
Recordset.RecordCount
 
sử dụng rowcount và phần chay truy vấn với tham số

rs.Open strSQL, conn,3,1

Mình k nhớ có chính xác k.
 
Cảm ơn bạn, OT cũng đã tìm hiểu và sử dụng câu lệnh trên (rs.Recordcount )
kết quả trả về - 1, trong khi dữ liệu trả về rất nhiều dòng. Phiền Bạn có thể hướng dẫn chi tiết hơn được không ạ?

RecordCount trong ADO Recordset chỉ chạy được với 3 loại "CursorType" là: adOpenKeySet (1), adOpenDynamic (2), adOpenStatic (3)
CursorType: adOpenForwardOnly(0) nó không đọc được nên trả về giá trị -1, tức là cho biết có record tồn tại thôi.
Nếu chuỗi kết nối không khai báo thì ADO sẽ sử dụng CursorType mặc định là: adOpenForwardOnly - 0
 
RecordCount trong ADO Recordset chỉ chạy được với 3 loại "CursorType" là: adOpenKeySet (1), adOpenDynamic (2), adOpenStatic (3)
CursorType: adOpenForwardOnly(0) nó không đọc được nên trả về giá trị -1, tức là cho biết có record tồn tại thôi.
Nếu chuỗi kết nối không khai báo thì ADO sẽ sử dụng CursorType mặc định là: adOpenForwardOnly - 0
Hic, cụ thể là thế nào vậy Anh?
OT muốn kiểm tra số dòng dữ liệu lấy từ DB vào Excel, trong trường hợp nếu dữ liệu đến 100,000 dòng thì báo lỗi dữ liệu quá nhiều trước khi đưa xuống bảng tính excel.
 
Hic, cụ thể là thế nào vậy Anh?
OT muốn kiểm tra số dòng dữ liệu lấy từ DB vào Excel, trong trường hợp nếu dữ liệu đến 100,000 dòng thì báo lỗi dữ liệu quá nhiều trước khi đưa xuống bảng tính excel.

:) Em dùng câu lênh như của quanluu1989 đó. Anh chỉ giải thích thêm là phải khai báo Recordset theo kiểu CursorType đó thì RecordCount mới trả về kết quả đúng.

Cách 1: dùng khai báo sớm nhé. (Early Binding)
Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
With oRS
.CursorType = adOpenKeyset
.CursorLocation = adUseClient
.LockType = adLockBatchOptimistic
.Open strSQL, oCnn
Msgbox "So dong: " & oRS.RecordCount
End With


Cách 2: như của quanluu1989
Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open strSQL, oCnn, adOpenKeyset, adLockBatchOptimistic
Msgbox "So dong: " & oRS.RecordCount
 
sử dụng rowcount và phần chay truy vấn với tham số

rs.Open strSQL, conn,3,1

Mình k nhớ có chính xác k.

:) Em dùng câu lênh như của quanluu1989 đó. Anh chỉ giải thích thêm là phải khai báo Recordset theo kiểu CursorType đó thì RecordCount mới trả về kết quả đúng.

Cách 1: dùng khai báo sớm nhé. (Early Binding)
Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
With oRS
.CursorType = adOpenKeyset
.CursorLocation = adUseClient
.LockType = adLockBatchOptimistic
.Open strSQL, oCnn
Msgbox "So dong: " & oRS.RecordCount
End With


Cách 2: như của quanluu1989
Dim oRS As ADODB.Recordset
Set oRS = New ADODB.Recordset
oRS.Open strSQL, oCnn, adOpenKeyset, adLockBatchOptimistic
Msgbox "So dong: " & oRS.RecordCount

Cảm ơn quanluu1989, cảm ơn Anh ongke0711
OT đã thử 2 cách của Anh ongke0711, cả 2 đều OK rồi ạ.
 
Nhờ các A/c xem giúp e lỗi này với ạ. Thank
 

File đính kèm

  • z1615532169924_63869c1fd5948bf4722f2b94b077ba69.png
    z1615532169924_63869c1fd5948bf4722f2b94b077ba69.png
    10 KB · Đọc: 17
  • So A-2018-3.xlsm
    So A-2018-3.xlsm
    1.6 MB · Đọc: 9
Lỗi này do cái ConnectString của bạn bị sai nên không open được
Xem lại cái Chr(39) trong chuỗi Connect. Nếu nhớ không nhầm thì Chr(39) là dấu nháy đơn (') thì phải
Cảm ơn a đã trợ giúp. e khắc phục được vấn đề của e rồi ạ.
Vấn đề của e là lỗi format định dạng ngày tháng. do lúc trước e để định dạng ngày tháng để so sánh dạng số (long), dữ liệu trong bảng dạng date nên khi so sánh bị ép kiểu dẫn đến chỉ làm được 1 số dòng sau đó báo lỗi runtime .. như trên.
Cách khắc phục của e là chuyển cái ngày tháng so sánh thành 1 string có định dạng theo cú pháp "mm-dd-yyyy". sau khi chuyển định dạng như vậy thì chạy ok rồi ạ.
 

File đính kèm

Xin chào các bạn.
Nhờ các bạn giúp tôi một câu lệnh truy vấn lấy ngày gần nhất so với thời điểm hiện tại trong database với ạ.
Cụ thể trong file đính kèm Sheet"Data" là bảng dữ liệu trong CSDL tôi cần truy vấn đến, và sheet KQ là dữ liệu mong muốn tôi cần lấy được từ bảng Data ạ.
 

File đính kèm

@OT thử, điều kiện là các ngày đều trong quá khứ và hiện tại
Mã:
Option Explicit
Sub a()
    Dim cnn As New ADODB.Connection
    Dim rs As New ADODB.Recordset
    Dim s As String
    s = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & " ;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
    cnn.Open s
    s = "SELECT * FROM [DATA$] WHERE DATE = (SELECT MAX(DATE) FROM [DATA$])"
    rs.Open s, cnn
    Sheets("KQ").Range("A2").CopyFromRecordset rs
    rs.Close
    Set rs = Nothing
    cnn.Close
    Set cnn = Nothing
End Sub
 
Xin chào các bạn.
Nhờ các bạn giúp tôi một câu lệnh truy vấn lấy ngày gần nhất so với thời điểm hiện tại trong database với ạ.
Cụ thể trong file đính kèm Sheet"Data" là bảng dữ liệu trong CSDL tôi cần truy vấn đến, và sheet KQ là dữ liệu mong muốn tôi cần lấy được từ bảng Data ạ.
Hỏi thêm:
- Data luôn được sắp xếp cột A (Date) từ nhỏ đến lớn?
- Trong Data có khi nào có ngày lớn hơn ngày hiện tại (Today()) không? Nếu có thì trước 1 ngày hoặc sau 1 ngày hiện tại thì lấy ngày nào?
- Số 20200299 thể hiện điều gì (Từ dòng 18594)
 
Lần chỉnh sửa cuối:
Hỏi thêm:
- Data luôn được sắp xếp cột A (Date) từ nhỏ đến lớn?
- Trong Data có khi nào có ngày lớn hơn ngày hiện tại (Today()) không? Nếu có thì trước 1 ngày hoặc sau 1 ngày hiện tại thì lấy ngày nào?
- Số 20200299 thể hiện điều gì (Từ dòng 18594)
Con chào Thầy,
Cảm ơn Thầy đã quan tâm ạ,
"20200299 " là do ngày hệ thống (phần mềm) tự sinh ra do người dùng trong quá trình nhập liệu không nhập ngày (nó sẽ lấy tháng năm của tháng hiện tại, còn ngày mặc định là 99)
Trong data không có ngày lớn hơn hiện tại Thầy ạ.
 
Con chào Thầy,
Cảm ơn Thầy đã quan tâm ạ,
"20200299 " là do ngày hệ thống (phần mềm) tự sinh ra do người dùng trong quá trình nhập liệu không nhập ngày (nó sẽ lấy tháng năm của tháng hiện tại, còn ngày mặc định là 99)
Trong data không có ngày lớn hơn hiện tại Thầy ạ.
Như vậy lúc nào ngày ở dòng cuối luôn là ngày gần nhất.
Cứ Filter ngày này là ra thôi.
 
@OT thử, điều kiện là các ngày đều trong quá khứ và hiện tại
Mã:
Option Explicit
Sub a()
    Dim cnn As New ADODB.Connection
    Dim rs As New ADODB.Recordset
    Dim s As String
    s = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & " ;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
    cnn.Open s
    s = "SELECT * FROM [DATA$] WHERE DATE = (SELECT MAX(DATE) FROM [DATA$])"
    rs.Open s, cnn
    Sheets("KQ").Range("A2").CopyFromRecordset rs
    rs.Close
    Set rs = Nothing
    cnn.Close
    Set cnn = Nothing
End Sub

Cảm ơn bạn đã giúp đỡ.
Trường hợp này OT hỏi về câu truy vấn trực tiếp trong SQL_Server ạ chứ không phải lấy từ Sheet DATA sang sheet KQ đâu ạ.
Tuy nhiên OT cũng đang cần đoạn code để lọc dạng này từ Sheet này sang Sheet khác, cảm ơn bạn đã cho OT một cách để tham khảo.
Vậy là câu lệnh OT cần để thực hiện trực tiếp trên SQL_Server là: "SELECT MAX(DATE) FROM DATA"
Cảm ơn bạn nhiều.
Chúc bạn nhiều sức khỏe.
Bài đã được tự động gộp:

Như vậy lúc nào ngày ở dòng cuối luôn là ngày gần nhất.
Cứ Filter ngày này là ra thôi.
Con chào Thầy
Con sử dụng câu lệnh "SELECT * FROM DATA" trong hệ thống xuất dữ liệu ra thì dữ liệu trong cột ngày sắp xếp y chang bảng data Thầy ạ (nguyên xi chưa chỉnh sửa gì ạ).
Nhìn vào "20200299" và "20200331" nó khác nhau 6 ký tự đầu về tháng/định dạng hệ thống là "yyymmdd1" có số 1 cuối cùngThầy ạ.
Nếu sử dụng VBA để lọc từ DATA sang sheet KQ giống như bài 74 thì cũng xử lý chuỗi ngày tháng này Thầy ạ.
Con cảm ơn Thầy.
Bài đã được tự động gộp:

@OT thử, điều kiện là các ngày đều trong quá khứ và hiện tại
Mã:
Option Explicit
Sub a()
    Dim cnn As New ADODB.Connection
    Dim rs As New ADODB.Recordset
    Dim s As String
    s = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & " ;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
    cnn.Open s
    s = "SELECT * FROM [DATA$] WHERE DATE = (SELECT MAX(DATE) FROM [DATA$])"
    rs.Open s, cnn
    Sheets("KQ").Range("A2").CopyFromRecordset rs
    rs.Close
    Set rs = Nothing
    cnn.Close
    Set cnn = Nothing
End Sub

Híc câu lệnh "SELECT MAX(DATE) FROM DATA" nó chỉ trả về duy nhất 1 giá trị của "20200331" trong cột DATE của bảng DATA.
OT muốn truy vân lấy tất cả các cột và dữ liệu là ngày max như bảng kết quả thì câu lệnh viết sao ạ T_T
 
Lần chỉnh sửa cuối:
Câu truy vấn là Select * from data where date=(select....)
Chính là biến s ở bài của mình.
 
Cảm ơn bạn đã giúp đỡ.
Trường hợp này OT hỏi về câu truy vấn trực tiếp trong SQL_Server ạ chứ không phải lấy từ Sheet DATA sang sheet KQ đâu ạ.
Tuy nhiên OT cũng đang cần đoạn code để lọc dạng này từ Sheet này sang Sheet khác, cảm ơn bạn đã cho OT một cách để tham khảo.
Vậy là câu lệnh OT cần để thực hiện trực tiếp trên SQL_Server là: "SELECT MAX(DATE) FROM DATA"
Cảm ơn bạn nhiều.
Chúc bạn nhiều sức khỏe.
Bài đã được tự động gộp:


Con chào Thầy
Con sử dụng câu lệnh "SELECT * FROM DATA" trong hệ thống xuất dữ liệu ra thì dữ liệu trong cột ngày sắp xếp y chang bảng data Thầy ạ (nguyên xi chưa chỉnh sửa gì ạ).
Nhìn vào "20200299" và "20200331" nó khác nhau 6 ký tự đầu về tháng/định dạng hệ thống là "yyymmdd1" có số 1 cuối cùngThầy ạ.
Nếu sử dụng VBA để lọc từ DATA sang sheet KQ giống như bài 74 thì cũng xử lý chuỗi ngày tháng này Thầy ạ.
Con cảm ơn Thầy.
Bài đã được tự động gộp:



Híc câu lệnh "SELECT MAX(DATE) FROM DATA" nó chỉ trả về duy nhất 1 giá trị của "20200331" trong cột DATE của bảng DATA.
OT muốn truy vân lấy tất cả các cột và dữ liệu là ngày max như bảng kết quả thì câu lệnh viết sao ạ T_T
Nếu có "20200331" và "20200399" ngày gần nhất là ngày nào?
 
Câu truy vấn là Select * from data where date=(select....)
Chính là biến s ở bài của mình.
A! Được rồi. Cảm ơn Bạn nhiều ^_^ ,, động đến cái SQL này cũng rắc rối nhỉ hic,,,
Dữ liệu không may có hư chắc mình ốm đòn với các Sếp quá!
Bài đã được tự động gộp:

Nếu có "20200331" và "20200399" ngày gần nhất là ngày nào?
Con chào Bác Hiếu,
Cảm ơn Bác Hiếu đã quan tâm ạ.
Trường hợp này con chưa gặp mà hệ thống cũng chỉ cho phép 1 tháng chỉ có một ngày
Vì đây là số liệu trong bản kiểm kê 1 tháng chỉ sảy ra 1 lần không có 2 ngày như vậy Bác ạ.
Chắc là cứ số nào to hơn thì là gần nhất thôi ạ. Híc.
Bài đã được tự động gộp:

A! Được rồi. Cảm ơn Bạn nhiều ^_^ ,, động đến cái SQL này cũng rắc rối nhỉ hic,,,
Dữ liệu không may có hư chắc mình ốm đòn với các Sếp quá!
Bài đã được tự động gộp:


Con chào Bác Hiếu,
Cảm ơn Bác Hiếu đã quan tâm ạ.
Trường hợp này con chưa gặp mà hệ thống cũng chỉ cho phép 1 tháng chỉ có một ngày
Vì đây là số liệu trong bản kiểm kê 1 tháng chỉ sảy ra 1 lần không có 2 ngày như vậy Bác ạ.
Chắc là cứ số nào to hơn thì là gần nhất thôi ạ. Híc.
Híc tháng 12 nó có 2 ngày luôn,, hình như tháng đó mới đưa data vào phần mềm nên nó vậy ạ T_T
 
Lần chỉnh sửa cuối:
A! Được rồi. Cảm ơn Bạn nhiều ^_^ ,, động đến cái SQL này cũng rắc rối nhỉ hic,,,
Dữ liệu không may có hư chắc mình ốm đòn với các Sếp quá!
Bài đã được tự động gộp:


Con chào Bác Hiếu,
Cảm ơn Bác Hiếu đã quan tâm ạ.
Trường hợp này con chưa gặp mà hệ thống cũng chỉ cho phép 1 tháng chỉ có một ngày
Vì đây là số liệu trong bản kiểm kê 1 tháng chỉ sảy ra 1 lần không có 2 ngày như vậy Bác ạ.
Chắc là cứ số nào to hơn thì là gần nhất thôi ạ. Híc.
Bài đã được tự động gộp:


Híc tháng 12 nó có 2 ngày luôn,, hình như tháng đó mới đưa data vào phần mềm nên nó vậy ạ T_T
Có 2 ngày "20200229" và "20200299"
 
Cái này phải bắt buộc nhập chuẩn dữ liệu từ phần mềm, chứ chẳng ai để như thế này cả, rất khó xử lý sau này.
 
Cái này phải bắt buộc nhập chuẩn dữ liệu từ phần mềm, chứ chẳng ai để như thế này cả, rất khó xử lý sau này.
Xin chào quanluu1989
Cảm ơn Bạn đã góp ý, phần mềm này của công ty OT cũng đang trong quá trình vừa thiết kế vừa sử dụng ạ, nên cũng có thể sẽ khó tránh khỏi lỗi thiết kế ạ.
 
Ví dụ dữ liệu chỉ tới tháng 2 năm 2020, ngày cuối sẽ là ngày nào?
Hic,con cũng không biết Bác ạ, nó còn tùy thuộc vào ngày mọi người thực hiện kiểm kê Bác ạ, thông thường là ngày cuối tháng cũng có thể là trước đó. Nếu chỉ có đến tháng 2 - loại bỏ ngày xx99 lấy ngày lớn nhất trong tháng 2 nếu không có thì mới lấy ngày 99 trong tháng 2 Bác ạ.
 
Hic,con cũng không biết Bác ạ, nó còn tùy thuộc vào ngày mọi người thực hiện kiểm kê Bác ạ, thông thường là ngày cuối tháng cũng có thể là trước đó. Nếu chỉ có đến tháng 2 - loại bỏ ngày xx99 lấy ngày lớn nhất trong tháng 2 nếu không có thì mới lấy ngày 99 trong tháng 2 Bác ạ.
Rắc rối rồi, SQL bài trước phải viết lại
 
Nếu lấy năm và tháng lớn nhất, trường hợp trong tháng đó chỉ có ngày 99 thì lấy ngày đó nếu có cả ngày khác trong tháng thì lấy max của ngày khác, câu truy vấn có thể dùng:
Mã:
SELECT *
FROM DATA
WHERE  date= (SELECT IIF(RIGHT(a,2)="00",a+99,a)
              FROM (SELECT MAX(IIF(RIGHT(date,2)="99",date-99,date)) AS a
                     FROM DATA));
Mục đích biến các ngày dạng yyyymm99 thành yyyymm00 để tìm max, tìm được max rồi nếu là ngày tháng bình thường thì giữ nguyên không thì chuyển lại về dạng yyyymm99.
 
Hic,dạ vâng có thể trong trường hợp dữ liệu con đưa lên là đúng nhưng trường hợp như Bác đang đề cập là gặp vấn đề ạ.
Nếu vậy thì câu lệnh SQL phải sửa lại sao vậy Bác.
Thử code
Mã:
Sub ABC()
  Dim cn As Object, rs As Object, SQL As String

  Set cn = CreateObject("ADODB.Connection")
  cn.Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=No""")
  SQL = "Select * From [DATA$] Where f1 = (Select Max(IIf(Mid(f1,7,2)=99,Mid(f1,1,6)&""00"",f1)) From [DATA$])"
  Set rs = cn.Execute(SQL)
  If Not rs.EOF() Then
    Sheets("sheet1").Range("A2").CopyFromRecordset rs
  End If
  rs.Close:    Set rs = Nothing
  cn.Close:    Set cn = Nothing
End Sub
 
Thử code
Mã:
Sub ABC()
  Dim cn As Object, rs As Object, SQL As String

  Set cn = CreateObject("ADODB.Connection")
  cn.Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=No""")
  SQL = "Select * From [DATA$] Where f1 = (Select Max(IIf(Mid(f1,7,2)=99,Mid(f1,1,6)&""00"",f1)) From [DATA$])"
  Set rs = cn.Execute(SQL)
  If Not rs.EOF() Then
    Sheets("sheet1").Range("A2").CopyFromRecordset rs
  End If
  rs.Close:    Set rs = Nothing
  cn.Close:    Set cn = Nothing
End Sub
Nếu lấy năm và tháng lớn nhất, trường hợp trong tháng đó chỉ có ngày 99 thì lấy ngày đó nếu có cả ngày khác trong tháng thì lấy max của ngày khác, câu truy vấn có thể dùng:
Mã:
SELECT *
FROM DATA
WHERE  date= (SELECT IIF(RIGHT(a,2)="00",a+99,a)
              FROM (SELECT MAX(IIF(RIGHT(date,2)="99",date-99,date)) AS a
                     FROM DATA));
Mục đích biến các ngày dạng yyyymm99 thành yyyymm00 để tìm max, tìm được max rồi nếu là ngày tháng bình thường thì giữ nguyên không thì chuyển lại về dạng yyyymm99.

Cảm ơn Bác HieuCD và Bạn Hau151978 nhiều ạ, đã cho OT 2 cách làm trên Excel và trong SQL.
Ngày mai đến cơ quan OT sẽ giả lập tình huống lỗi như đã đề cập để test thử ạ, nếu có vấn đề gì OT sẽ thông tin lại ở đây ạ.
Chúc mọi người nhiều sức khỏe, thân nhiện luôn luôn nằm trong tiêu chuẩn trong mùa chống dịch này ạ.
 
Cảm ơn Bác HieuCD và Bạn Hau151978 nhiều ạ, đã cho OT 2 cách làm trên Excel và trong SQL.
Ngày mai đến cơ quan OT sẽ giả lập tình huống lỗi như đã đề cập để test thử ạ, nếu có vấn đề gì OT sẽ thông tin lại ở đây ạ.
Chúc mọi người nhiều sức khỏe, thân nhiện luôn luôn nằm trong tiêu chuẩn trong mùa chống dịch này ạ.

Xin chào Bác HieuCD và Bạn Hau151978
OT thử tạo tình huống lỗi sảy ra,sửa ô A28205:
20200331 thành 20200499
Thì dữ liệu lọc sang sheets("KQ")
Code cho sub B ok, cho sub ABC chưa được ạ.
Mã:
Sub B()
    'Hau151978
    Dim cnn As New ADODB.Connection
    Dim rs As New ADODB.Recordset
    Dim s As String
    s = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & " ;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
    cnn.Open s
    s = "SELECT * FROM [DATA$] " & _
        "WHERE DATE = (SELECT IIF(RIGHT(a,2)=""00"",a+99,a) " & _
        "FROM (SELECT MAX(IIF(RIGHT(DATE,2)=""99"",DATE-99,DATE)) AS a " & _
        "FROM [DATA$]));"

    rs.Open s, cnn
    Sheets("KQ").Range("A2:K10000").ClearContents
    Sheets("KQ").Range("A2").CopyFromRecordset rs
    rs.Close
    Set rs = Nothing
    cnn.Close
    Set cnn = Nothing
End Sub


Sub ABC()

    'HieuCD
    Dim cn As Object, rs As Object, SQL As String

    Set cn = CreateObject("ADODB.Connection")
    cn.Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=No""")
    SQL = "Select * From [DATA$] Where f1 = (Select Max(IIf(Mid(f1,7,2)=99,Mid(f1,1,6)&""00"",f1)) From [DATA$])"
    
    Set rs = cn.Execute(SQL)
    Sheets("KQ").Range("A2:K10000").ClearContents
    If Not rs.EOF() Then
        
        Sheets("KQ").Range("A2").CopyFromRecordset rs
    End If
    
    rs.Close:    Set rs = Nothing
    cn.Close:    Set cn = Nothing
    
End Sub
 

File đính kèm

@OT trong code B nếu chạy trên máy mình sẽ không ra kết quả, không biết sao máy bạn lại chạy được
s = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & " ;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
chỗ "Excel 12.0 Xml" chỉ đúng khi lấy dữ liệu file xlsx còn xlsm là Excel 12.0 macro hoặc Excel 12.0, xlsb là Excel 12.0
Code ABC kia chưa đúng vì khi max là ngày 99 thì Select Max(IIf(Mid(f1,7,2)=""99"",Mid(f1,1,6)&""00"",f1)) From [DATA$] sẽ ra ngày 00, lúc đó sẽ không tìm được record nào có ngày đó.
 
Lần chỉnh sửa cuối:
@OT trong code B nếu chạy trên máy mình sẽ không ra kết quả, không biết sao máy bạn lại chạy được
s = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & " ;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
chỗ "Excel 12.0 Xml" chỉ đúng khi lấy dữ liệu file xlsx còn xlsm là Excel 12.0 macro hoặc Excel 12.0, xlsb là Excel 12.0

Xin chào Hau151978,
Khi đọc thông tin trên của Bạn , OT thấy trong cùng thư mục xlsm vẫn còn tập tin xlsx , OT thử xóa xlsx đi thậm trí di truyển tập tin xlsm sang một thư mục mới và chạy sub B vẫn có kết quả.
OT không hiểu ADO sau khi chạy lần đầu tiên nó có lưu dữ liệu đâu không nữa T_T
Untitled.jpg
 
Cũng có thể do may mắn, máy mình thử chạy 3 lần không được, xóa chữ xml đi là được ngay. Tốt nhất cứ theo hướng dẫn ở đây thôi.
 
Xin chào Bác HieuCD và Bạn Hau151978
OT thử tạo tình huống lỗi sảy ra,sửa ô A28205:
20200331 thành 20200499
Thì dữ liệu lọc sang sheets("KQ")
Code cho sub B ok, cho sub ABC chưa được ạ.
Mã:
Sub B()
    'Hau151978
    Dim cnn As New ADODB.Connection
    Dim rs As New ADODB.Recordset
    Dim s As String
    s = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & " ;Extended Properties=""Excel 12.0 Xml;HDR=YES"";"
    cnn.Open s
    s = "SELECT * FROM [DATA$] " & _
        "WHERE DATE = (SELECT IIF(RIGHT(a,2)=""00"",a+99,a) " & _
        "FROM (SELECT MAX(IIF(RIGHT(DATE,2)=""99"",DATE-99,DATE)) AS a " & _
        "FROM [DATA$]));"

    rs.Open s, cnn
    Sheets("KQ").Range("A2:K10000").ClearContents
    Sheets("KQ").Range("A2").CopyFromRecordset rs
    rs.Close
    Set rs = Nothing
    cnn.Close
    Set cnn = Nothing
End Sub


Sub ABC()

    'HieuCD
    Dim cn As Object, rs As Object, SQL As String

    Set cn = CreateObject("ADODB.Connection")
    cn.Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=No""")
    SQL = "Select * From [DATA$] Where f1 = (Select Max(IIf(Mid(f1,7,2)=99,Mid(f1,1,6)&""00"",f1)) From [DATA$])"
   
    Set rs = cn.Execute(SQL)
    Sheets("KQ").Range("A2:K10000").ClearContents
    If Not rs.EOF() Then
       
        Sheets("KQ").Range("A2").CopyFromRecordset rs
    End If
   
    rs.Close:    Set rs = Nothing
    cn.Close:    Set cn = Nothing
   
End Sub
Chỉnh lại
Mã:
Sub ABC()
  Dim cn As Object, rs As Object, SQL As String

  Set cn = CreateObject("ADODB.Connection")
  cn.Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=no""")
  SQL = "Select * From [DATA$] Where IIf(Mid(f1,7,2)=99,Mid(f1,1,6)&""00"",f1) = (Select Max(IIf(Mid(f1,7,2)=99,Mid(f1,1,6)&""00"",f1)) From [DATA$])"
  Set rs = cn.Execute(SQL)
  If Not rs.EOF() Then
    Sheets("sheet1").Range("A2").CopyFromRecordset rs
  End If
  rs.Close:    Set rs = Nothing
  cn.Close:    Set cn = Nothing
End Sub
 
Chỉnh lại
Mã:
Sub ABC()
  Dim cn As Object, rs As Object, SQL As String

  Set cn = CreateObject("ADODB.Connection")
  cn.Open ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & ThisWorkbook.FullName & ";Extended Properties=""Excel 12.0;HDR=no""")
  SQL = "Select * From [DATA$] Where IIf(Mid(f1,7,2)=99,Mid(f1,1,6)&""00"",f1) = (Select Max(IIf(Mid(f1,7,2)=99,Mid(f1,1,6)&""00"",f1)) From [DATA$])"
  Set rs = cn.Execute(SQL)
  If Not rs.EOF() Then
    Sheets("sheet1").Range("A2").CopyFromRecordset rs
  End If
  rs.Close:    Set rs = Nothing
  cn.Close:    Set cn = Nothing
End Sub

Cũng có thể do may mắn, máy mình thử chạy 3 lần không được, xóa chữ xml đi là được ngay. Tốt nhất cứ theo hướng dẫn ở đây thôi.

Xin chào Bác HieuCD,
Code trên của Bác con thử chạy được rồi ạ, cảm ơn Bác Hiếu.

Xin chào Hau151978,
Cảm ơn Bạn, OT đã sửa lại câu lệnh connection strings theo link bạn gửi kèm rồi ạ.
Kết quả vẫn lấy được số liệu.. hay thậy có thể do OT sử dụng phiên bản Office 365 nên có gì đó khác khác.
OT chưa thử các phiên bản office khác.
 
Mình cũng dùng 365, vừa thử khởi động lại máy thì thấy lại chạy được với Excel 12.0 xml. Chắc lúc trước máy mình có vấn đề.
 
Xin chào các Bạn,

Nhờ các Bạn giúp đỡ OT sử dụng ADO/SQL để thực hiện trường hợp sau với ạ:
Từ bảng "DULIEU" lọc duy nhất 3 cột MAHANG,TENHANG,CHUNGLOAI,sau đó tính tổng số lượng theo vùng công thức màu hồng tím dựa vào điều kiện từ ngày đến ngày. Kết quả mong như bảng "TH_MH" ạ.
OT sử dụng câu lệnh "SELECT DISTINCT MAHANG,TENHANG,CHUNGLOAI" thì lấy được dữ liệu duy nhất của 3 trường, nhưng chưa biết cách tính toán cho vùng công thức màu hồng ạ.


DL.jpg

TH.jpg
 

File đính kèm

Xin chào các Bạn,

Nhờ các Bạn giúp đỡ OT sử dụng ADO/SQL để thực hiện trường hợp sau với ạ:
Từ bảng "DULIEU" lọc duy nhất 3 cột MAHANG,TENHANG,CHUNGLOAI,sau đó tính tổng số lượng theo vùng công thức màu hồng tím dựa vào điều kiện từ ngày đến ngày. Kết quả mong như bảng "TH_MH" ạ.
OT sử dụng câu lệnh "SELECT DISTINCT MAHANG,TENHANG,CHUNGLOAI" thì lấy được dữ liệu duy nhất của 3 trường, nhưng chưa biết cách tính toán cho vùng công thức màu hồng ạ.


View attachment 236068

View attachment 236069
Không biết ADO, viết bằng VBA được không?
 

File đính kèm

Không biết ADO, viết bằng VBA được không?
Con chào Thầy ạ,
Dạ được chứ Thầy, vì hiện giờ con đang sử dụng công thức ạ. Về dạng dữ liệu kiểu này con đang sử dụng nhiều, Vba có thể ứng dụng đư nhiều tình huống khác ạ.
Con muốn hỏi thêm phương pháp ADO/SQL để lấy dữ liệu trực tiếp từ SQL_Server mà không cần phải đưa dữ liệu về Excel nữa .
Con cảm ơn Thầy nhiều ạ,
Chúc Thầy nhiều sức khỏe ạ.
 
Xin chào các Bạn,

Nhờ các Bạn giúp đỡ OT sử dụng ADO/SQL để thực hiện trường hợp sau với ạ:
Từ bảng "DULIEU" lọc duy nhất 3 cột MAHANG,TENHANG,CHUNGLOAI,sau đó tính tổng số lượng theo vùng công thức màu hồng tím dựa vào điều kiện từ ngày đến ngày. Kết quả mong như bảng "TH_MH" ạ.
OT sử dụng câu lệnh "SELECT DISTINCT MAHANG,TENHANG,CHUNGLOAI" thì lấy được dữ liệu duy nhất của 3 trường, nhưng chưa biết cách tính toán cho vùng công thức màu hồng ạ.


View attachment 236068

View attachment 236069
Bạn tìm hiểu group by nhé. Mình khuyên là nên viết procedure ở phía server, code vba chi để truyền tham số và thực thi thôi.
vi du:
select mahang, sum(line_01)
from table
group by mahang
 
Bạn tìm hiểu group by nhé. Mình khuyên là nên viết procedure ở phía server, code vba chi để truyền tham số và thực thi thôi.
vi du:
select mahang, sum(line_01)
from table
group by mahang

Xin chào quanluu1989,
Cảm ơn Bạn đã góp ý, đúng là khi lấy một lượng dữ liệu lớn từ máy chủ về thì nên thực hiện trực tiếp qua Sever ạ.
Vba trong trường hợp này vẫn có thể sử dụng được ạ,nếu dữ liệu không quá nhiều(khoảng hai trăm nghìn dòng trở xuống- do số lượng bản ghi đã khống chế từ câu lệnh lấy dữ liệu từ mày chủ).
Nhưng để đảm bảo có thể tổng hợp dữ liệu ở một khoảng thời gian dài thì việc sử dụng vba có thể sẽ bị treo do dữ liệu lấy về quá nhiều ạ.
Với ví dụ trên OT chưa hiểu và nắm bắt được phiền bạn giúp đỡ OT làm viết câu lệnh select theo tất cả điều kiện tín toán trong cột "TONG CONG" được không ạ.
Cảm ơn Bạn nhiều.
 

Bài viết mới nhất

Back
Top Bottom