Phần 5: Tạo báo cáo với C#
Chức năng báo cáo (Report) là chức năng yêu cầu cần có ở hầu hết các ứng dụng lập trình với cơ sở dữ liệu. Ưu điểm của báo cáo để cho người sử dụng có tổng kết nhanh tình hình kinh doanh, có thể in ấn và xuất ra các định dạng dữ liệu khác một cách dễ dàng. Các loại báo cáo thường gặp như báo cáo doanh thu theo tháng, theo quý hoặc theo năm, báo cáo hàng tồn kho …
Trong bài này chúng ta sẽ tiếp tục phần tạo báo cáo với Cơ sở dữ liệu đã trình bày ở phần 4.
Yêu cầu bài toán
Cho cơ sở dữ liệu QLBanHang có các bảng:
tblMatHang( MaSP nchar(5), TenSP nvarchar(30), NgaySX Date, NgayHH Date, DonVi nvarchar(10), DonGia float , GhiChu nvarchar(200))
tblNhaCC(MaNhaCC nchar(5), TenNhaCC nvarchar(50), DiaChi nvarchar(200), MaSoThue nvarchar(15), TaiKhoan nvarchar(15), DienThoai nvarchar(11))
tblHangNhap(MaSP nchar(5), MaNhaCC nchar(5), SoLuong int, DonGia float, SoHD nvarchar(10), NgayGH Date)
Tạo các báo cáo làm các chức năng sau:
- Báo cáo thống kê các mặt hàng nhập trong ngày
- Báo cáo danh sách các mặt hàng theo từng hoá đơn, cho phép nhập vào số hoá đơn.
- Báo cáo 10 nhà cung cấp có số tiền nhập cao nhất
>Xem hướng dẫn tạo Database trong VisualStudio
Hướng dẫn tạo báo cáo
> Xem hướng dẫn chi tiết.
Trong hướng dẫn ở trên, chúng ta chỉ tạo báo cáo cho một bảng. Với báo cáo lấy dữ liệu từ nhiều bảng, để đơn giản chúng ta có thể tạo Stored Procedure rồi sau đó gọi tên Procedure đó trong code.
Ví dụ báo cáo thống kê các mặt hàng nhập trong ngày câu lệnh sẽ như sau:
CREATE PROCEDURE dbo.BCMHNhapTheoNgay
@NgayGH DateTime
AS
SELECT A.MaSP, TenSP, TenNhaCC,DiaChi,SoLuong,A.DonGia,SoHD
FROM tblHangNhap as A, tblMatHang as B, tblNhaCC C
WHERE A.MaSP = B.MaSP and A.MaNhaCC = C.MaNhaCC and NgayGH = @NgayGH
-
Hướng dẫn cài đặt control ReportViewer trong Visual Studio 2019
-
Xem video hướng dẫn tạo Stored Procedure
-
Xem video hướng dẫn tạo mẫu báo cáo
-
Xem video hướng dẫn code hiển thị báo cáo
Tham khảo thêm
- Bài giảng lập trình Cơ sở dữ liệu với ADO.NET
- Các bài học sử dụng SQL Server
- Các câu lệnh SQL căn bản
- Hướng dẫn tạo báo cáo với ReportViewer
- Hướng dẫn tạo báo cáo với Crystal Report
- Xây dựng chương trình quản lý bán hàng bằng C#
- Chuẩn viết code .Net
thầy ơi trong nhóm bọn em có 3 người chia phần mỗi bạn làm 1 form con làm thế nào để ghép bài ạ bọn e ghép toàn báo lỗi thôi ạ
Em gửi cho mình xem thông báo lỗi gì?
Chú ý khi ghép bài, vì mỗi bạn làm một form khác nhau trong đó có kết nối tới CSDL thì khi copy code sang, các em phải chỉnh sửa lại chuỗi kết nối tới CSDL.
Để copy ít bị lỗi hơn, em mở 2 project đồng thời rồi ở cửa sổ Solution Explorer, em copy form từ project này rồi paste tới project kia.
thầy ơi thầy cho em hỏi là trong phần from thống kế báo cáo của e có 2 lỗi thầy xem hộ e với ạ
namespace BaiTapLon
{
public partial class frmBCMHnhap : Form
{
public frmBCMHnhap()
{
InitializeComponent();
}
private void frmBCMHnhap_Load(object sender, EventArgs e)
{
this.rpvBCMHNhap.RefreshReport();
}
private void button1_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = Properties.Settings.Default.QuanlibanhangConnectionString;
SqlCommand cmd = new SqlCommand();
cmd.CommandText = “BCMMHnhapTheoThang”;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
cmd.Parameters.Add(new SqlParameter(“@NgayGH”,dtpNgayGH.Value.Date));
//khai báo dataset để lấy dữ liệu
DataSet ds = new DataSet();
SqlDataAdapter dap = new SqlDataAdapter(cmd);
dap.Fill(ds);
//thiết lập báo cáo
rpvBCMHNhap.ProcessingMode = ProcessingMode.Local;
rpvBCMHNhap.LocalReport.reportPath = “rptBCMHNhap.rdlc”;
if (ds.Tables[0].Rows.Count > 0)
{
ReportDataSource rds = new ReportDataSource();
rds.Name = “dsMaHangNhap”;
rds.Value = ds.Tables[0];
//gắn lên mẫu báo cáo
rpvBCMHNhap.LocalReport.DataSources.Clear();
rpvBCMHNhap.LocalReport.DataSources.Add(rds);
rpvBCMHNhap.RefreshReport();
}
}
}
}
Error 1 The name ‘dtpNgayGH’ does not exist in the current context D:\SV\BaiTapLon\BaiTapLon\frmBCMHnhap.cs 37 59 BaiTapLon
Error 2 ‘Microsoft.Reporting.WinForms.LocalReport’ does not contain a definition for ‘reportPath’ and no extension method ‘reportPath’ accepting a first argument of type ‘Microsoft.Reporting.WinForms.LocalReport’ could be found (are you missing a using directive or an assembly reference?) D:\SV\BaiTapLon\BaiTapLon\frmBCMHnhap.cs 44 37 BaiTapLon
Lỗi 1: dtpNgayGH là control DateTimePicker để nhập vào ngày tháng. E phải kéo vào form rồi đặt tên thuộc tính Name la dtpNgayGH
Lỗi 2: em sử dụng thuộc tính không đúng. Tên thuộc tính là ReportPath
e thưa thầy e có làm một form đổi mật khẩu với code như sau:
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace BTLQuanLyKho.View
{
public partial class frmDoiMK : Form
{
public static string pass;
// chuỗi kết nối
string strConnection = @”Data Source=USERNAM-VJEJT5S\DUONGMINHTU;Initial Catalog=QLKho;Integrated Security=True”;
SqlConnection conn;
SqlCommand cmd;
//string sql = “SELECT * FROM [QLKho].[dbo].[DangNhap]”;
public frmDoiMK()
{
InitializeComponent();
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
}
private Boolean kiemtrarong()
{
Boolean kq = false;
if (txtMkcu.Text == “”)
{
MessageBox.Show(“Bạn chưa nhập mật khẩu cũ!”);
txtMkcu.Focus();
kq = true;
}
else if (txtMkmoi.Text == “”)
{
MessageBox.Show(“Bạn chưa nhập mật khẩu mới!”);
txtMkmoi.Focus();
kq = true;
}
else if (txtNhaplai.Text == “”)
{
MessageBox.Show(“Bạn chưa nhập lại mật khẩu mới!”);
txtNhaplai.Focus();
kq = true;
}
return kq;
}
private void btnDoimk_Click(object sender, EventArgs e)
{
if (kiemtrarong() == false)
{
if (txtMkcu.Text == frmDoiMK.pass)
{
if (txtMkmoi.Text == txtNhaplai.Text)
{
string matkhau = txtMkmoi.Text;
string capnhat = “UPDATE DangNhap SET Password='” + matkhau + “‘ WHERE Username=’admin’;”;
conn = new SqlConnection(strConnection);
cmd = new SqlCommand(capnhat, conn);
conn.Open();
cmd.ExecuteNonQuery();
MessageBox.Show(“Đổi mật khẩu thành công”, “Thông báo”);
conn.Close();
}
else
{
MessageBox.Show(“Mật khẩu xác nhận không đúng vui lòng kiểm tra lại!”, “Thông báo”, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
txtMkmoi.Text = “”;
txtNhaplai.Text = “”;
}
}
else
{
MessageBox.Show(“Mật khẩu hiện tại không đúng vui lòng kiểm tra lại!”);
txtMkcu.Text = “”;
txtMkmoi.Text = “”;
txtNhaplai.Text = “”;
}
}
}
private void btnThoat_Click(object sender, EventArgs e)
{
this.Close();
}
private void frmDoiMK_Load(object sender, EventArgs e)
{
}
}
}
nhưng e không biết cách làm để đổ data của pass cũ để so sánh với pass cũ mình nhập có giống nhau không nên nó toàn thông báo “mật khẩu hiện tại không đúng”
thầy giúp e sửa code với ạ
em xin cảm ơn
Theo code bạn gửi thì bạn thiết kế Form có 3 TextBox:
– 1 TextBox cho nhập mật khẩu cũ
– 1 TextBox cho nhập mật khẩu mới
– 1 TextBox bắt người sử dụng nhập lại mật khẩu mới
Nhưng câu lệnh if (txtMkcu.Text == frmDoiMK.pass) => Biến pass này em lấy dữ liệu ở đâu? Làm sao để so sánh được chứ nên luôn luôn nó nhày đến thông báo lỗi như của em thôi.
ở chỗ đáp.Fill(đs); nó báo lỗi này em phải khắc phục như thế nào thưa thầy?
An unhandled exception of type ‘System.Data.SqlClient.SqlException’ occurred in System.Data.dll
Additional information: Procedure or function ‘BCPNTheoNgay’ expects parameter ‘@NgayNhap’, which was not supplied.
Trong câu lệnh SQL mình có một tham số truyền vào là @NgayNhap => bạn cần truyền vào ngày này. Bạn xem lại code nhé.
thầy cho em hỏi em có một database đã tạo bằng sql server thì làm thế nào để sử dụng nó như tỏng phần 4.4 của thầy
Em vào cửa sổ Server Explorer, kích vào biểu tượng có hình Database có phích cắm (Connect to Database), sau đó có cửa sổ Choose Data Source hiển thị ra => Chọn Microsoft SQL Server =>Rồi em điền các thông số như tên Server, User, Pass và tên Database của em vào là sẽ làm được giống như phần 4.4.
thầy cho em hỏi, trong bảng lọc thống kê của em, em muốn thêm một thuộc tính lọc theo ngày (vd: tìm các hóa đơn từ ngày X đến ngày Y), em có viết một Store để lọc, nhưng khi truyền dữ liệu từ C# vào SQL thì không được nhận do type date của winform C# và SQL server không giống nhau. Thầy có thể hướng dẫn em cách chỉnh sửa không ạ
Gửi cho mình code store và phần code c# em truyền vào store.
Dạ đây là store
create proc spTongSoHoaDon
(
@Ngay1 date,
@Ngay2 date
)
as
Begin
select COUNT(MaHD)
from HoaDon
where Ngay between @Ngay1 and @Ngay2
End
còn phần này là code C#:
public DataTable DemHoaDon_Ngay(string Ngay1, string Ngay2)
{
return db.ExecuteQueryDataSet(“exec spTongSoHoaDon ” + Ngay1 + “,” + Ngay2 + “”, CommandType.Text, null);
}
public DataTable ExecuteQueryDataSet(string strSQL, CommandType ct, params SqlParameter[] p)
{
if (conn.State == ConnectionState.Open)
conn.Close();
conn.Open();
comm.CommandText = strSQL;
comm.CommandType = ct;
da = new SqlDataAdapter(comm);
DataTable ds = new DataTable();
da.Fill(ds);
return ds;
}
Đoạn code em viết rối quá.
Em chỉ cần viết như sau:
public DataTable ExecuteQueryDataSet(string sql, string Ngay1, string Ngay2)
{
if (conn.State == ConnectionState.Open)
conn.Close();
conn.Open();
comm.CommandText = sql;
comm.CommandType = CommandType.StoreProcedured;
comm.Parameters.AddWithValue(“@Ngay1”,Ngay1);
comm.Parameters.AddWithValue(“@Ngay2”,Ngay2);
da = new SqlDataAdapter(comm);
DataTable ds = new DataTable();
da.Fill(ds);
return ds;
}
thầy ơi
Cho em hỏi làm sao để thêm sản phẩm vào hoá đơn cùng lúc 2 bảng hoá đơn với chi tiết hoá đơn vậy thầy
Code như thế nào v thầy
em muốn chọn sảnphẩm sau đó thêm vào bên chi tiết hoá đơn gồm có MaSP,TenSP,Giá,SL,Thành Tiền.
khi load lại hoá đơn có sao để k hiện lại hoá đơn cũ trên girlConTrol
Em cảm ơn thầy
– Để thêm dữ liệu vào 2 bảng cùng một lúc, em viết 2 câu lệnh SQL insert. Khi kích nút thêm dữ liệu thì sẽ thêm truyền từng câu lệnh SQL vào và thực hiện ExcuteNonQuery() với từng câu lệnh SQL đó. Chú ý nếu 2 bảng em Insert có quan hệ cha – con (ví dụ Hoá Đơn và Hoá Đơn chi tiết) thì em Insert vào bảng Hoá Đơn trước rồi sau đó mới Insert vào bảng hoá đơn chi tiết.
Ví dụ viết vào sự kiện btnThem_Click(….)
SqlCommand cmd = new SqlCommand();
cmd.CommandText = sql1;//Câu lệnh insert vào Hoá đơn
cmd.Connection = con;//Đối tượng Connection
cmd.ExecuteNonQuery();
cmd.CommandText = sql2;//Câu lệnh insert vào Hoá đơn chi tiết
cmd.Connection = con;//Đối tượng Connection
cmd.ExecuteNonQuery();
thầy ơi, phần tblHangNhap thì của e chia làm tblChitietHDN và tblHoadonnhap thì phải làm sao thầy?
Để tạo báo bảo mà dữ liệu lấy từ nhiều bảng, trước hết em phải tạo Store Procedured để Select dữ liệu từ các bảng này.
Sau đó em thiết kế báo cáo theo các cột em select từ câu lệnh truy vấn này.
Em xem chi tiết lại bài này:
https://timoday.edu.vn/phan-5-tao-bao-cao-voi-c/
nếu thế e phải join dữ liệu từ 4 bảng hả thầy? Mong thầy giải đáp ạ
4 bảng hay bao nhiêu bảng thì em làm tương tự như bài trên. Em phải viết câu lệnh truy vấn và lưu dưới dạng Store Procedure rồi mới thiết kế báo cáo theo Store này.
Thầy cho em hỏi là làm thế nào để form cho người dùng chọn tháng, năm và in ra báo cáo từng ngày trong tháng đó ạ? vì êm thấy datetimepicker chỉ cho phép chọn ngày, tháng, năm chứ ko cho chọn riêng tháng,năm!
thầy ơi cho em hỏi muốn làm báo cáo mặt hàng bán chạy nhất trong tháng thì làm như thế nào ah, và em code như video hướng dẫn nhưng lúc chọn ngày thì không lọc ra ngày mình đã chọn mà sổ ra tất cả các ngày nhập hàng ah lỗi này sửa như thế nào ah.
Thưa thầy khi đã đưa ra được báo cáo giống vậy mà em muốn xuất ra excel để in ra thì làm như thế nào à
Công cụ report nó đã có sẵn cho em xuất ra các loại tệp khác nhau như Excel, PDF hoặc Word. Em xem ở biểu tượng cái đĩa ở trên thanh công cụ của Report.
thầy ơi. e có 5 file pdf khác nhau, trong form e có danh sách 5 người. khi click vào người nào thì sẽ mở file pdf tương ứng người đó lên có được k thầy?
Được chứ em. Nhưng để làm được việc đó:
1. Em dùng phần mềm nào để hiển thị file PDF đó, thì cần chọn thư viện tương ứng
2. Trên form phải có đường dẫn chính xác tới file PDF đó.
Em có thể tham khảo một giải pháp ở đây:
https://www.c-sharpcorner.com/UploadFile/hirendra_singh/how-to-show-pdf-file-in-C-Sharp/
Thầy ơi làm sao để báo cáo danh sách mà dạng tìm theo năm ạ theo kiểu datetimepicker ạ
Thưa thầy cho e hỏi e muốn tạo 1 stored procedures báo cáo hàng tồn kho từ ngày đến ngày khác gồm 2 bảng hàng nhập(MaMH, NgayNhap, ….) và hàng xuất (MaMH, NgayXuat, …) e có viết 1 stored nhưng ko hiện mong thầy giúp e chỉnh sửa.
create proc dbo.HangTonKho
@NgayNhap date,@NgayXuat date
as
begin
select dbo.HangNhap.MaMH, dbo.HangNhap.TenMH,(dbo.HangNhap.SoLuong-dbo.HangXuat.SoLuong) as SLHangTon,GiaNhap
from dbo.HangNhap, dbo.HangXuat
where dbo.HangNhap.MaMH = dbo.HangXuat.MaMH and NgayNhap = @NgayXuat
end
Của em báo lỗi gì? Mình thấy đang câu lệnh có vẻ đang bị nhầm phần điều kiện where. Em thử store này xem:
Nhưng em cần kiểm tra lại, vì phần tính tồn kho của em như thế này không đúng đâu nhé.
Thưa thầy e xin lỗi làm phiền thầy. Em đã viết lại csdl nhưng khi chạy trên sql vs vs đều mất dữ liệu, mong thầy sửa giúp e.
create proc dbo.HangTonKho
@TuNgay date,@DenNgay date
as
begin
SELECT A.MaMH,dbo.HangNhap.TenMH,dbo.NhaCC.TenNCC ,(TSLNhap – ISNULL(TSLXuat,0)) as SLHangTon,dbo.HangNhap.GiaNhap from
(SELECT dbo.HangNhap.MaMH,SUM(SoLuong) as TSLNhap FROM dbo.HangNhap GROUP BY MaMH) as A full join
(SELECT MaMH, SUM(SoLuong) as TSLXuat FROM DBO.HangXuat GROUP BY MaMH) as B
on A.MaMH=b.MaMH left join dbo.HangNhap on B.MaMH = dbo.HangNhap.MaMH left join dbo.NhaCC on dbo.HangNhap.MaNCC = dbo.NhaCC.MaNCC
left join dbo.HangXuat on dbo.HangNhap.MaMH = dbo.HangXuat.MaMH
where dbo.HangXuat.NgayXuat between @TuNgay and @DenNgay
end
Vì em chưa có kinh nghiệm nên không thể viết phát chạy được ngay đâu. Em nên mở dạng cửa sổ query ra và chạy thử xem ra kết quả hay không. Ví dụ em chạy:
SELECT A.MaMH,dbo.HangNhap.TenMH,dbo.NhaCC.TenNCC ,(TSLNhap – ISNULL(TSLXuat,0)) as SLHangTon,dbo.HangNhap.GiaNhap from
(SELECT dbo.HangNhap.MaMH,SUM(SoLuong) as TSLNhap FROM dbo.HangNhap GROUP BY MaMH) as A full join
(SELECT MaMH, SUM(SoLuong) as TSLXuat FROM DBO.HangXuat GROUP BY MaMH) as B
on A.MaMH=b.MaMH left join dbo.HangNhap on B.MaMH = dbo.HangNhap.MaMH left join dbo.NhaCC on dbo.HangNhap.MaNCC = dbo.NhaCC.MaNCC
left join dbo.HangXuat on dbo.HangNhap.MaMH = dbo.HangXuat.MaMH
where dbo.HangXuat.NgayXuat between “01/01/2020” and “06/01/2020”
Khi chạy OK thì em mới thay vào phần Store Procedured của em.
Có thể em cần chạy từng đoạn để test chắc chắn kết quả chạy đúng.
thầy ơi em gặp lỗi này thì sửa sao dc ạ.
an error occurred during local report processing. the report definition for report ‘BCTN’ has not been specified
Nó không tìm thấy cái file report thiết kế của em. Em xem báo cáo “BCTN” em đang để ở đâu? em thử copy vào thử mục bin/Debug xem sao
em làm giống thầy nhưng cái ngày để load báo cáo ra thì n không theo ngày ạ. 2 sản phẩm khác ngày nhưng vẫn ra ở report @@ . thầy có thể utraview cho em ko ạ. em cảm ơn
Store em vẫn khai báo: @NgayGH DateTime, cái control DateTimePiker cho chọn ngày tháng, em chọn Format => Long
thầy ơi e using Microsoft.Reporting.WinForms; mà cứ bị lỗi ở chỗ WinForms là sao thầy
chụp ảnh đi em
private void btReport_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = Properties.Settings.Default.TTConnectionString;
SqlCommand cmd = new SqlCommand();
cmd.CommandText = “ticket”;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;
cmd.Parameters.Add(new SqlParameter(“@date”,dateTimePicker1.Value.Date));
TTDataSet1 ds = new TTDataSet1();
SqlDataAdapter dap = new SqlDataAdapter(cmd);
dap.Fill(ds);
reportViewer1.ProcessingMode = ProcessingMode.Local;
reportViewer1.LocalReport.ReportPath = “Report1.rdlc”;
if( ds.Tables[0].Rows.Count > 0)
{
ReportDataSource rsd = new ReportDataSource();
rsd.Name = “DataSet1”;
rsd.Value = ds.Tables[0];
reportViewer1.LocalReport.DataSources.Clear();
reportViewer1.LocalReport.DataSources.Add(rsd);
reportViewer1.RefreshReport();
}
thầy ơi em làm như thầy nhưng với table k phải store thì nó báo lỗi tại Fill h mình sửa đâu ạ
Nếu không phải là store thì em truyền trực tiếp câu lệnh SQL, ví dụ:
SqlCommand cmd = new SqlCommand();
cmd.CommandText = “Select * from tblSanPham where Ngay >=” + dateTimePicker1.Value.Date.ToString();
cmd.Connection = con;
Em chào a, e cài report như a hướng dẫn mà ko đc.
vào project có phần cài report mà ở phần add lại ko tìm thấy.
link ảnh của e, mong a hướng dẫn: https://www.mediafire.com/file/xnas64kpfcj6szy/b.png/file
e dùng visual 2022