SQL where clause not getting filtered - sql

I have the following query, but it is not giving any regard to the in the p.created_by =#searchBy where clause, how to correct it so that the results would be filtered according #searchBy too.
ALTER PROC [dbo].[Rptcashcollectionouter] #branchId INT,
#searchBy INT,
#strDate DATETIME=NULL,
#endDate DATETIME=NULL
AS
BEGIN
SELECT DISTINCT p.created_on AS paid_date
FROM reading re
JOIN billing_gen bg ON re.id = bg.reading_id
JOIN customer_registration cr ON bg.account_number = cr.account_number
JOIN payment p ON bg.bill_number = p.bill_number
JOIN customer_category cc ON cr.customer_category_id = cc.id
WHERE p.created_by = #searchBy
AND ( ( #strDate IS NULL )
OR Cast(Floor(Cast(p.created_on AS FLOAT)) AS DATETIME) >=
Cast(Floor(Cast(#strDate AS FLOAT)) AS DATETIME) )
AND ( ( #endDate IS NULL )
OR Cast(Floor(Cast(p.created_on AS FLOAT)) AS DATETIME) <=
Cast(Floor(Cast(#endDate AS FLOAT)) AS DATETIME) )
AND cr.branch_id = #branchId
ORDER BY p.created_on ASC;
END;

Check the value inside your procedure as below.
SELECT #branchId, #searchBy, #strDate,#endDate
And, then try to run the SQL manually with the same value. Also, make sure you have data in your table for your criteria.
Also, what exactly you are trying here ?
Cast(Floor(Cast(p.created_on AS FLOAT)) AS DATETIME)

While executing procedure, make sure you are passing properly value.
Print out all values that are coming (Just for testing).
#searchBy INT is of integer type. But i think "p.created_by =#searchBy" is a type of datetime or date , so it may also conflicts here, or display wrong result. In below line. p.created_by is treating as a datetime or date and #searchby in integer.
WHERE p.created_by = #searchBy

Related

how to execute procedure with multiply arguement?

create proc [dbo].[SSRproc] (
#StartDate Date
,#EndDate Date
,#DepartmentGroupKey int
)
as begin
select F.Date,
F.AccountKey,
F.Amount,
F.OrganizationKey,
O.OrganizationName,
F.DepartmentGroupKey,
D.DepartmentGroupName
from [AdventureWorksDW2017].[dbo].[FactFinance] as f
inner join dbo.DimOrganization as O on F.OrganizationKey = O.OrganizationKey
inner join dbo.DimDepartmentGroup as D on F.DepartmentGroupKey = D.DepartmentGroupKey
where F.Date between #StartDate and #EndDate and #DepartmentGroupKey = F.DepartmentGroupKey
end
[dbo].[SSRproc] '2010-12-29', '2011-01-29', (3,5)
here is my procedure code and at the end I have execution but I need DepartmentGroupKey has multiply argument like key will be (3,5) or (3,8,9) and like that what I have to do?
If your Procedure is called from where a Table Valued Parameter is supported that would be the best solution. But if your Procedure is called from somewhere else this is not always possible so here is a alternative.
create proc [dbo].[SSRproc] (
#StartDate Date
,#EndDate Date
,#DepartmentGroupKey varchar(10)
)
as begin .....
.....and F.DepartmentGroupKey in (select value from STRING_SPLIT(#DepartmentGroupKey)
And then the execute:
execute dbo.SSRproc
#DepartmentGroupKey = '3,5'

How to improve while loop insert performance in sql server?

Here is my SQL Query. It's insert almost 6500+ row from temp table. But its takes 15+ mins! . How can i improve this ? Thanks
ALTER proc [dbo].[Process_bill]
#userid varchar(10),
#remark nvarchar(500),
#tdate date ,
#pdate date
as
BEGIN
IF OBJECT_ID('tempdb.dbo..#temptbl_bill', 'U') IS NOT NULL
DROP TABLE #temptbl_bill;
CREATE TABLE #temptbl_bill (
RowID int IDENTITY(1, 1),
------------
)
// instert into temp table
DECLARE #NumberRecords int, #RowCounter int
DECLARE #batch INT
SET #batch = 300
SET #NumberRecords = (SELECT COUNT(*) FROM #temptbl_bill)
SET #RowCounter = 1
SET NOCOUNT ON
BEGIN TRANSACTION
WHILE #RowCounter <= #NumberRecords
BEGIN
declare #clid int
declare #hlid int
declare #holdinNo nvarchar(150)
declare #clientid nvarchar(100)
declare #clientName nvarchar(50)
declare #floor int
declare #radius nvarchar(50)
declare #bill money
declare #others money
declare #frate int
declare #due money
DECLARE #fine money
DECLARE #rebate money
IF #RowCounter > 0 AND ((#RowCounter % #batch = 0) OR (#RowCounter = #NumberRecords))
BEGIN
COMMIT TRANSACTION
PRINT CONCAT('Transaction #', CEILING(#RowCounter/ CAST(#batch AS FLOAT)), ' committed (', #RowCounter,' rows)');
BEGIN TRANSACTION
END;
// multiple select
// insert to destination table
Print 'RowCount -' +cast(#RowCounter as varchar(20)) + 'batch -' + cast(#batch as varchar(20))
SET #RowCounter = #RowCounter + 1;
END
COMMIT TRANSACTION
PRINT CONCAT('Transaction #', CEILING(#RowCounter/ CAST(#batch AS FLOAT)), ' committed (',
#RowCounter,' rows)');
SET NOCOUNT OFF
DROP TABLE #temptbl_bill
END
GO
As has been said in comments, the loop is completely unnecessary. The way to improve the performance of any loop is to remove it completely. Loops are a last resort in SQL.
As far as I can tell your insert can be written with a single statement:
INSERT tbl_bill(clid, hlid, holdingNo,ClientID, ClientName, billno, date_month, unit, others, fine, due, bill, rebate, remark, payment_date, inserted_by, inserted_date)
SELECT clid = c.id,
hlid = h.id,
h.holdinNo ,
c.cliendID,
clientName = CAST(c.clientName AS NVARCHAR(50)),
BillNo = CONCAT(h.holdinNo, MONTH(#tdate), YEAR(#tdate)),
date_month = #tDate,
unit = 0,
others = CASE WHEN h.hfloor = 0 THEN rs.frate * (h.hfloor - 1) ELSE 0 END,
fine = bs.FineRate * b.Due / 100,
due = b.Due,
bill = #bill, -- This is declared but never assigned
rebate = bs.rebate,
remark = #remark,
payment_date = #pdate,
inserted_by = #userid,
inserted_date = GETDATE()
FROM ( SELECT id, clientdID, ClientName
FROM tbl_client
WHERE status = 1
) AS c
INNER JOIN
( SELECT id, holdinNo, [floor], connect_radius
FROM tx_holding
WHERE status = 1
AND connect_radius <> '0'
AND type = 'Residential'
) AS h
ON c.id = h.clid
LEFT JOIN tbl_radius_setting AS rs
ON rs.radius= CONVERT(real,h.connect_radius)
AND rs.status = 1
AND rs.type = 'Non-Govt.'
LEFT JOIN tbl_bill_setting AS bs
ON bs.Status = 1
LEFT JOIN
( SELECT hlid,
SUM(netbill) AS Due
FROM tbl_bill AS b
WHERE date_month < #tdate
AND (b.ispay = 0 OR b.ispay IS NULL)
GROUP BY hlid
) AS b
ON b.hlid = h.id
WHERE NOT EXISTS
( SELECT 1
FROM tbl_bill AS tb
WHERE EOMONTH(#tdate) = EOMONTH(date_month)
AND tb.holdingNo = h.holdinNo
AND (tb.update_by IS NOT NULL OR tb.ispay=1)
);
Please take this with a pinch of salt, it was quite hard work trying to piece together the logic, so it may need some minor tweaks and corrections
As well as adapting this to work as a single statement, I have made a number of modifications to your existing code:
Swapped NOT IN for NOT EXISTS to avoid any issues with null records. If holdingNo is nullable, they are equivalent, if holdingNo is nullable, NOT EXISTS is safer - Not Exists Vs Not IN
The join syntax you are using was replaced 27 years ago, so I switched from ANSI-89 join syntax to ANSI-92. - Bad habits to kick : using old-style JOINs
Changed predicates of YEAR(date_month) = YEAR(#tDate) AND MONTH(date_month) = MONTH(#tDate) to become EOMONTH(#tdate) = EOMONTH(date_month). These are syntactically the same, but EOMONTH is Sargable, whereas MONTH and YEAR are not.
Then a few further links/suggestions that are directly related to changes I have made
Although I removed the while lopp, don't fall into the trap of thinking this is better than a cursor. A properly declared cursor will out perform a while loop like yours - Bad Habits to Kick : Thinking a WHILE loop isn't a CURSOR
The general consensus is that prefixing object names is not a good idea. It should either be obvious from the context if an object is a table/view or function/procedure, or it should be irrelevant - i.e. There is no need to distinguish between a table or a view, and in fact, we may wish to change from one to the other, so having the prefix makes things worse, not better.
The average ratio of time spent reading code to time spent writing code is around 10:1 - It is therefore worth the effort to format your code when you are writing it so that it is easy to read. This is hugely subjective with SQL, and I would not recommend any particular conventions, but I cannot believe for a second you find your original code free flowing and easy to read. It took me about 10 minutes just unravel the first insert statement.
EDIT
The above is not correct, EOMONTH() is not sargable, so does not perform any better than YEAR(x) = YEAR(y) AND MONTH(x) = MONTH(y), although it is still a bit simpler. If you want a truly sargable predicate you will need to create a start and end date using #tdate, so you can use:
DATEADD(MONTH, DATEDIFF(MONTH, '19000101', #tdate), '19000101')
to get the first day of the month for #tdate, then almost the same forumla, but add months to 1st February 1900 rather than 1st January to get the start of the next month:
DATEADD(MONTH, DATEDIFF(MONTH, '19000201', #tdate), '19000201')
So the following:
DECLARE #Tdate DATE = '2019-10-11';
SELECT DATEADD(MONTH, DATEDIFF(MONTH, '19000101', #tdate), '19000101'),
DATEADD(MONTH, DATEDIFF(MONTH, '19000201', #tdate), '19000201');
Will return 1st October and 1st November respectively. Putting this back in your original query would give:
WHERE NOT EXISTS
( SELECT 1
FROM tbl_bill AS tb
WHERE date_month >= DATEADD(MONTH, DATEDIFF(MONTH, '19000101', #tdate), '19000101'),
AND date_month < DATEADD(MONTH, DATEDIFF(MONTH, '19000201', #tdate), '19000201')
AND tb.holdingNo = h.holdinNo
AND (tb.update_by IS NOT NULL OR tb.ispay=1)
);

Not Supplying Value to Parameter In SP throwing Error- sql server 2008

i have a SP as given below.
CREATE PROCEDURE CHKIndex
#count DECIMAL(10,2) ,
#ID INT = NULL,
#DATE VARCHAR (MAX)
AS
SELECT DISTINCT
COL1,
COL2
FROM
(
SELECT COL1,COL2,rn
FROM TAB1 T1
INNER JOIN TAB2 T2 ON T1.SNO = T2.PNO
)t
where t.rn = 1
AND DATE = #DATE
AND t.ID = #ID
GO
When i executed like EXEC CHKIndex 20,71,22082016
It is working fine when i supplied value for all three parameter,
but
starts giving error when not supplied any value for date as
Procedure or function 'uspECP_Competitive_Index' expects parameter '#DATE', which was not supplied.
i am trying to modify in such a way that if user want to see data based on only #count and #ID
they can able to do so.
if i assign default NULL for #date even than not getting any records in the output.
Please suggest.
A quick and dirty way could be to modify your where clause to be:
WHERE
t.rn = 1
AND DATE = ISNULL(#DATE, DATE)
AND t.ID = #ID
A couple of other points to note are
You are not using the parameter #count
It would make much more sense to use the datetime type for your #Date parameter, rather than varchar(max).

How to return a list of courses between 2 months in SQL Server 2012 Management Studio?

How to create a stored procedure in SQL Server 2012 that returns a list of courses running between 2 months?
I've written code something like this:
create procedure final_RTrainerqualification
(#TrainerID char(10),
#Coursecode char(4) OUTPUT,
#qualcode nvarchar(30),
#coursedate datetime output)
DECLARE #MinDate DATE = '20160401',
#MaxDate DATE = '20160601';
SELECT coursedate
FROM dbo.RTrainerqualification
WHERE coursedate >= #MinDate
AND coursedate < #MaxDate;`
It should be returning the list of courses that run between these 2 dates mentioned but I am new to stored procedure so my question is how do I assign coursedates to the courses and make it return the list?
Edit- used T-SQL to recreate the code
#Coursecount smallint
declare #Coursedatebeg datetime, #Coursedateend datetime, #CourseCode char(4),#TrainerID char(10);
select #Coursedatebeg = '2015-04-20'
select #Coursedateend = '2015-06-20';
while #Coursedatebeg <= #Coursedateend
begin
select #CourseCode = #Coursedateend;
select #Coursecount = count(*) from RCourseInstance
where CourseCode between 'R222' and 'R224';
if #CourseCount <> 0
begin
Print 'Courses running between April and June 2015 ' ;
select Coursedate,CourseCode from RCourseInstance as t
inner join Coursedate as d on t.Coursedate = d.Coursedate
inner join CourseCode as c on c.CourseCode = t.CourseCode
where CourseCode between 'R222' and 'R224';
end
else
print 'No courses are running between these dates ' ;
set #Coursedatebeg = #Coursedatebeg + 2;
end
It is returning the print statement but also declaring that invalid object name Coursedate
what have I done incorrectly here?
Firstly, use ISO date strings to avoid regional settings issues. You are only returning the coursedate in the SELECT. If you want further information such as the coursecode then add it into the SELECT. i.e.
DECLARE #MinDate DATE = '2016-04-01',
#MaxDate DATE = '2016-06-01'
SELECT coursedate, coursecode, *
FROM dbo.RTrainerqualification
WHERE coursedate >= #MinDate
AND coursedate < #MaxDate;
The OUTPUT variables are not required - these are needed when you want to return a single value rather than a list.
This is fundamental SQL stuff so I would strongly recommend you do some reading on this. There is a simple stored procedure tutorial here to start off with.

SQL -- Selecting Top 1 with Order by?

This was resolved. The statement was in another part of the stored procedure.
The stored procedure I'm writing won't allow me to do this:
declare #dtTopDate datetime
select top 1 #dtTopDate = date_build
from database..table
where database..table.parent = #Parent
and database..table.child = #Child
order by date_build desc
Gives me this error:
Column "database..table.date_build" is
invalid in the ORDER BY clause because
it is not contained in either an
aggregate function or the GROUP BY
clause.
What am I doing wrong?
[Edit] There is no group by statement here. SQL2005.
Here is some more context:
if #Notify = 0
begin
declare #dtTopDate datetime
select top 1 #dtTopDate = date_build
from database..table
where database..table.parent = #Parent
and database..table.child = #Child
order by date_build desc
insert
into database2..table
(parent, child, notification_date, change_date)
values (#Parent, #Child, #dtTopDate, getdate())
return
end
This works for me, but I'm not sure if this is what you are trying to do b/c your example has some errors.
use Test
go
CREATE TABLE [dbo].[MyTable]
(
[MyTableId] [uniqueidentifier] NOT NULL,
[MyDate] [datetime] NOT NULL,
CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED([MyTableId] ASC,[MyDate] ASC)
)
GO
CREATE PROCEDURE ProcTopDate
(
#MyDate datetime OUT
)
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 1
#MyDate = [MyDate]
FROM [Test].[dbo].[MyTable]
order by MyDate
END
GO
insert into MyTable(MyTableId, MyDate)
values(newid(), getdate())
go
declare #MyDate datetime
exec ProcTopDate #MyDate OUT
print #MyDate
Instead of SELECT TOP 1 ... ORDER BY ...
Why not try SELECT MAX( ..
DECLARE #dtTopDate datetime
SELECT #dtTopDate = MAX(date_build)
from database..table
where database..table.parent = #Parent
and database..table.child = #Child
What version of SQL are you using? It works fine for me on MS SQL Server 2005 (ionce I fix the declaration).
Honestly the only thing I can see wrong is that #dtTopDate =/= #dtLatestDate
Apart from that, there is no GROUP BY clause in your SQL statement.
I just ran this and it worked fine.
declare #OrderDate datetime
select top 1 #OrderDate = OrderDate
from Orders
where Orders.CustomerID = 'ALFKI'
and Orders.EmployeeID = 4
order by OrderDate desc
SELECT #OrderDate
Try qualifying the columns correctly to avoid any ambiguities or x-database schema issue
declare #dtTopDate datetime
select top 1
#dtTopDate = [database]..[table].date_build
FROM
[database]..[table]
where
[database]..[table].parent = #Parent
and [database]..[table].child = #Child
order by
[database]..[table].date_build desc
Or alias it
declare #dtTopDate datetime
select top 1
#dtTopDate = foo.date_build
FROM
[database]..[table] foo
where
foo.parent = #Parent
and foo.child = #Child
order by
foo.date_build desc
The problem was in another part of the stored procedure. I was using a count(*) elsewhere and it required a group by. Thanks for the help.
Try SELECT #dtLatestDate = TOP 1 date_build...
if you want to get really tricky, in T-SQL you can try using the row_number() method and an inner select:
select * from
(
select
db.groupId
, db.date_build
, date_build_rank = row_number() over ( partition by db.groupId order by db.date_build desc)
from
#date_build_tbl db
) as a
where a.date_build_rank < 2;