Reputation: 45
I have a table in SQL Server which lists sections in a report. There are three fields, a SectionID (numeric autonumber primary key), SectionTitle (title for the section on the report) and SourceView (name of the view in the local db which returns the records for the report).
What I need is a view which has these three columns plus a fourth column which shows the number of records returned by the 'SourceView'. Something like:
CREATE myView AS
SELECT
SectionID,
SectionTitle,
SourceView,
myFunction(SourceView) AS RowsInView
FROM
tblBaseData
I thought this would be simple to achieve by writing a function to take in the view name and return the number of rows. My original plan was to build some dynamic SQL in the body of the function.
CREATE FUNCTION myFunction(@ViewName VARCHAR) RETURNS INT AS
BEGIN
DECLARE @RowCount INT
DECLARE @SQL VARCHAR(200)
SET @SQL = 'SET @RowCount = (SELECT COUNT(*) FROM ' + @ViewName + ')'
EXEC sp_executesql @SQL
RETURN ISNULL(@RowCount, 0)
END
However, you can't use EXEC within a function so you can't run dynamic SQL, you can't use EXEC to run a procedure which returns a value, and you can't query the system objects because - although this will work for tables - it won't work for views.
I have tried the following without success:
How to get the row count for views from a database?
Execute function inside view SQL server
https://msdn.microsoft.com/en-GB/library/ms188655.aspx
Create a function for counting rows from any table
I am trying to get a view working because I need to display the results on a web-page with current record counts, otherwise I would build a table and refresh the data periodically,
I assume that I'm just using the wrong approach to this problem. Can anyone point me in the right direction? Thanks.
Upvotes: 2
Views: 3201
Reputation: 4048
This is rather clumsy but using a procedure rather than a view would get round the problems you have addressed in your question:
CREATE PROCEDURE GetViewRowCounts
AS
BEGIN
DECLARE @sectionId int, @title varchar(50), @view varchar(50)
DECLARE @tbl_view_counts TABLE (section_id int not null,
title varchar(50) not null,
view_name varchar(50) not null,
view_count int not null)
DECLARE @RowCount INT
DECLARE @SQL NVARCHAR(200), @ParmDefinition NVARCHAR(100)
DECLARE c_vws CURSOR FAST_FORWARD FOR
SELECT
SectionID,
SectionTitle,
SourceView
FROM
tblBaseData
OPEN c_vws
FETCH NEXT FROM c_vws INTO @sectionId, @title, @view
WHILE @@FETCH_STATUS = 0
BEGIN
SET @ParmDefinition = N'@RowCountOUT int OUTPUT';
SET @SQL = N'SELECT @RowCountOUT = COUNT(*) FROM ' + @view
EXEC sp_executesql @SQL, @ParmDefinition, @RowCountOUT=@RowCount OUTPUT;
INSERT @tbl_view_counts
VALUES (@sectionId, @title, @view, @RowCount)
FETCH NEXT FROM c_vws INTO @sectionId, @title, @view
END
CLOSE c_vws
DEALLOCATE c_vws
SELECT * FROM @tbl_view_counts
END
Upvotes: 1
Reputation: 391
This will give you the count back without having to use a function or know the name of the view:
CREATE myView AS
SELECT
SectionID,
SectionTitle,
SourceView,
COUNT(*) OVER() AS RowsInView
FROM
tblBaseData
EDIT: Apologies, I misread your initial post. I agree that a stored procedure is probably the best way to go, but if you wanted to continue with a view approach, you could have a "lookup" view, like this:
CREATE VIEW dbo.ViewCounts
AS
SELECT 'SourceView1' AS SourceViewName,
COUNT(*) OVER () AS RowsInView
FROM SourceView1
UNION
SELECT 'SourceView2' AS SourceViewName,
COUNT(*) OVER () AS RowsInView
FROM SourceView2
-- etc...
Then join back onto it in your original view to get the count this way:
CREATE myView AS
SELECT
t.SectionID,
t.SectionTitle,
t.SourceView,
vc.RowsInView
FROM
tblBaseData t
JOIN dbo.ViewCounts vc ON vc.SourceViewName = t.SourceView
It's a very dirty approach (and the ViewCounts view will need manually updating if you add new views), but could solve your problem if you absolutely need to persist with a view.
Upvotes: 1