Parameter is missing a value - reporting-services

May you please assist me with this issue
I have created a report that receives 5 parameters
#Site - Location Name
#StartDate
#EndDate
#StartTime
#EndTime
All seems to be working fine, the report filters according to what is required. The problem is now the same rdl file I need to publish it on another system and emmediately after publishing when I run it gives me this error "Reportviewer - specific report error: The 'StartTime' parameter is missing a value ;0;Void Error(System.String, System.Object[])"
Am not sure where to look into at this moment as I don't experience the error when running report on my local. Below is the code I used:
Parameters
#StartDate default = dateadd(dateinterval.Day, -1, Today)
#EndDate default = =dateadd(dateinterval.Day, -1, Today)
#SiteID SQL Dataset = SELECT 0 AS ID, 'All' as Name
FROM sites
UNION
SELECT ID, Name
FROM sites
#StartTime default = 12:00:00 AM
Available values (12:00:00 AM - 11:00:00 PM
#EndTime default = 11:00:00 M
Available values (12:00:00 AM - 11:00:00 PM
SQL Dataset
Declare #Start datetime = cast (#StartDate + ' '+ #StartTime as datetime)
Declare #End datetime = cast(#EndDate + ' ' + #EndTime as datetime )
SELECT Distinct ast.Name as HomeSite, ISNULL(c.FirstName + ' ', '') + c.LastName as Name, md.MemRefNo,att2.Name as VisitedSite,isnull(att2.TotalVisits,0) as TotalVisits, isnull(atc.totalaccepted,0) TotalAcceptedVisits, ISNULL(att.TotalOverrideVisits, 0) AS TotalOverrideVisits, isnull(att1.TotalOverrideDenieds,0) as TotalOverrideDenieds
FROM Contacts c
INNER JOIN MemberDetail md on md.ContactGUID = c.GUID
INNER JOIN Sites ast on c.HomeSiteID = ast.ID
OUTER APPLY
(
SELECT ast.Name,a1.contactguid,COUNT(*) totalaccepted
FROM Attendance a1
INNER JOIN Sites ast on a1.SiteID = ast.ID
WHERE a1.contactguid = c.GUID
AND (a1.IsSwipeSuccessful = 1)
AND a1.accessoverridereasonid IS NULL
AND a1.AttendDate BETWEEN #Start AND #End
AND (a1.SiteID = #SiteID OR #SiteID = 0)
group by a1.contactguid,ast.Name
)atc
OUTER APPLY
(
SELECT ast.Name,a2.contactguid,COUNT(*) TotalOverrideVisits
FROM Attendance a2
INNER JOIN Sites ast on a2.SiteID = ast.ID
WHERE a2.contactguid = c.GUID
AND a2.accessoverridereasonid IS NOT NULL
AND a2.AttendDate BETWEEN #Start AND #End
AND (a2.SiteID = #SiteID OR #SiteID = 0)
group by a2.contactguid,ast.Name
) att
Outer APPLY
(
SELECT ast.Name,a3.contactguid,COUNT(*) TotalOverrideDenieds
FROM Attendance a3
INNER JOIN Sites ast on a3.SiteID = ast.ID
WHERE a3.contactguid = c.GUID
AND a3.IsSwipeSuccessful = 0
AND a3.AttendDate BETWEEN #Start AND #End
AND (a3.SiteID = #SiteID OR #SiteID = 0)
group by a3.contactguid,ast.Name
) att1
Cross APPLY
(
SELECT ast.Name,a3.contactguid,COUNT(*) TotalVisits
FROM Attendance a3
INNER JOIN Sites ast on a3.SiteID = ast.ID
WHERE a3.contactguid = c.GUID
AND a3.AttendDate BETWEEN #Start AND #End
AND (a3.SiteID = #SiteID OR #SiteID = 0)
group by a3.contactguid,ast.Name
) att2
Order by name

Try refreshing all the datasets (shared and non-shared)
Check their properties (especially the parameters page) and make
sure they are right.
Redeploy (make sure you are overwrite existing datasets)
Hope this helps,
Henro

Related

Mysql select counters grouped by time with gaps filled [duplicate]

How i can fill date gaps in MySQL? Here is my query:
SELECT DATE(posted_at) AS date,
COUNT(*) AS total,
SUM(attitude = 'positive') AS positive,
SUM(attitude = 'neutral') AS neutral,
SUM(attitude = 'negative') AS negative
FROM `messages`
WHERE (`messages`.brand_id = 1)
AND (`messages`.`spam` = 0
AND `messages`.`duplicate` = 0
AND `messages`.`ignore` = 0)
GROUP BY date ORDER BY date
It returns proper result set - but i want to fill gaps between dates start and end by zeros. How i can do this?
You'll need to create a helper table and fill it with all dates from start to end, then just LEFT JOIN with that table:
SELECT d.dt AS date,
COUNT(*) AS total,
SUM(attitude = 'positive') AS positive,
SUM(attitude = 'neutral') AS neutral,
SUM(attitude = 'negative') AS negative
FROM dates d
LEFT JOIN
messages m
ON m.posted_at >= d.dt
AND m.posted_at < d.dt + INTERVAL 1 DAYS
AND spam = 0
AND duplicate = 0
AND ignore = 0
GROUP BY
d.dt
ORDER BY
d.dt
Basically, what you need here is a dummy rowsource.
MySQL is the only major system which lacks a way to generate it.
PostgreSQL implements a special function generate_series to do that, while Oracle and SQL Server can use recursion (CONNECT BY and recursive CTEs, accordingly).
I don't know whether MySQL will support the following/similar syntax; but if not, then you could just create and drop a temporary table.
--Inputs
declare #FromDate datetime, /*Inclusive*/
#ToDate datetime /*Inclusive*/
set #FromDate = '20091101'
set #ToDate = '20091130'
--Query
declare #Dates table (
DateValue datetime NOT NULL
)
set NOCOUNT ON
while #FromDate <= #ToDate /*Inclusive*/
begin
insert into #Dates(DateValue) values(#FromDate)
set #FromDate = #FromDate + 1
end
set NOCOUNT OFF
select dates.DateValue,
Col1...
from #Dates dates
left outer join SourceTableOrView data on
data.DateValue >= dates.DateValue
and data.DateValue < dates.DateValue + 1 /*NB: Exclusive*/
where ...?

MySQL Query Issues with Math not resulting in expected output

Overview:
I built an application that I run locally which allows me to keep track of my kids chores and behaviors that they exhibit on a daily basis. This system has negative and positive behaviors I can assign to them which correspond to a point value on a 100 point scale.
Logic:
The query only looks at the current day to calculate the points. If ratings were received the day prior, those will not play into their daily total.
100 points is the maximum a child can have for the day, even if their ratings cause them to exceed this, it will always return as 100.
If they don't have any ratings for the day (either positive or negative), it will default their points to the starting point 100.
When they receive points, their total will adjust accordingly, either going up or down based on the value set for the behavior.
Scenarios:
New day without any ratings means the child starts at 100 points. They receive a negative behavior that has a -3 value. This would return their totalPoints as 97.
The above child then receives a positive rating worth 2 points which brings them up to 99 for their totalPoints.
They receive another positive rating worth 5 points. Since we max out at 100, we would return their totalPoints as 100, regardless of how much it exceeded 100.
Issue:
I built the query and thought everything was working fine but there seems to be a slight math issue with it. When the child received a -3 point rating it brought them to 97 which was expected. I then gave them a positive 4 and it brought their score to 99 instead of 100 like I would have expected.
Query:
SELECT c.id,
c.NAME,
Date_format(From_days(Datediff(CURRENT_DATE, c.age)),
'%y Years %m Months %d Days') AS age,
c.photoname,
c.photonamesmall,
(SELECT CASE
WHEN ( Ifnull(Sum(t.points), (SELECT settingvalue
FROM settings
WHERE settingname = 'MaxPoints')
) >= (
SELECT
settingvalue
FROM
settings
WHERE
settingname = 'MaxPoints') ) THEN 100
WHEN ( Sum(t.points) <= 0 ) THEN ( (SELECT settingvalue
FROM settings
WHERE settingname =
'MaxPoints')
+ Sum(t.points) )
ELSE ( (SELECT settingvalue
FROM settings
WHERE settingname = 'MaxPoints') -
Ifnull(Sum(t.points), (SELECT
settingvalue
FROM settings
WHERE
settingname = 'MaxPoints')) )
END
FROM behaviorratings AS r
JOIN behaviortypes AS t
ON r.behaviorid = t.behaviortypeid
WHERE r.childid = c.id
AND Date_format(r.timestamp, '%Y-%m-%d') = Curdate()) AS
totalPoints,
(SELECT definitionname
FROM behaviordefinitions AS d
WHERE totalpoints BETWEEN d.min AND d.max) AS
behaviorRating
FROM children AS c
Fiddle:
Here is a link to the SQL fiddle: http://sqlfiddle.com/#!9/fa06c/1/0
The result I expect to see for Child 2 (Brynlee) is 100 not 99.
She started with 100, received a -3 and the received a +4. While I know the math for this order of operations is correct, I need to it to be tweaked to reflect how I expected it to be reflected. 100 - 3 = 97 and then 97 + 4 = 101 (We max out at 100 so 100 would be the totalPoints.
Try this
SELECT c.id,
c.name,
DATE_FORMAT(
FROM_DAYS(
DATEDIFF(CURRENT_DATE, c.age)
),
'%y Years %m Months %d Days'
) AS age,
c.photoName,
c.photoNameSmall,
(SELECT CASE
WHEN ( Ifnull(Sum(t.points), 0
) + (SELECT settingValue
FROM settings
WHERE settingName = 'MaxPoints') >= (
SELECT
settingValue
FROM
settings
WHERE
settingName = 'MaxPoints') ) THEN 100
WHEN ( Sum(t.points) <= 0 ) THEN ( (SELECT settingValue
FROM settings
WHERE settingName =
'MaxPoints')
+ Sum(t.points) )
ELSE ( (SELECT settingValue
FROM settings
WHERE settingName = 'MaxPoints') -
Ifnull(Sum(t.points), (SELECT
settingvalue
FROM settings
WHERE
settingName = 'MaxPoints')) )
END
FROM behaviorRatings AS r
JOIN behaviorTypes AS t
ON r.behaviorID = t.behaviorTypeID
WHERE r.childid = c.id
AND Date_format(r.timestamp, '%Y-%m-%d') = Curdate()) AS
totalPoints,
(SELECT definitionName
FROM behaviorDefinitions AS d
WHERE totalPoints BETWEEN d.min AND d.max) AS
behaviorRating
FROM children AS c
Basically, using
WHEN ( Ifnull(Sum(t.points), (SELECT settingvalue
FROM settings
WHERE settingname = 'MaxPoints')
)
will only give you 100 when sum(t.points) is null. To get total points you need to do
Ifnull(Sum(t.points), 0) + (SELECT settingvalue
FROM settings
WHERE settingname = 'MaxPoints')
This sql may make it easier to look at
SET #maxPoints := (SELECT settingValue
FROM settings
WHERE settingName = 'MaxPoints');
SELECT c.id,
c.name,
DATE_FORMAT(
FROM_DAYS(
DATEDIFF(CURRENT_DATE, c.age)
),
'%y Years %m Months %d Days'
) AS age,
c.photoName,
c.photoNameSmall,
(SELECT CASE
WHEN ( Ifnull(Sum(t.points), 0) + #maxPoints > #maxPoints ) THEN 100
ELSE ( Ifnull(Sum(t.points), 0) + #maxPoints )
END
FROM behaviorRatings AS r
JOIN behaviorTypes AS t
ON r.behaviorID = t.behaviorTypeID
WHERE r.childid = c.id
AND Date_format(r.timestamp, '%Y-%m-%d') = Curdate()) AS
totalPoints,
(SELECT definitionName
FROM behaviorDefinitions AS d
WHERE totalPoints BETWEEN d.min AND d.max) AS
behaviorRating
FROM children AS c
Using 50 as starting point:
SET #maxPoints := (SELECT settingValue
FROM settings
WHERE settingName = 'MaxPoints');
SET #startingPoint := 50;
SELECT c.id,
c.name,
DATE_FORMAT(
FROM_DAYS(
DATEDIFF(CURRENT_DATE, c.age)
),
'%y Years %m Months %d Days'
) AS age,
c.photoName,
c.photoNameSmall,
(SELECT CASE
WHEN ( Ifnull(Sum(t.points), 0) + #startingPoint > #maxPoints ) THEN 100
ELSE ( Ifnull(Sum(t.points), 0) + #startingPoint )
END
FROM behaviorRatings AS r
JOIN behaviorTypes AS t
ON r.behaviorID = t.behaviorTypeID
WHERE r.childid = c.id
AND Date_format(r.timestamp, '%Y-%m-%d') = Curdate()) AS
totalPoints,
(SELECT definitionName
FROM behaviorDefinitions AS d
WHERE totalPoints BETWEEN d.min AND d.max) AS
behaviorRating
FROM children AS c
Sql for applying capping once total points exceeding limitation
SET #maxPoints := (SELECT settingValue
FROM settings
WHERE settingName = 'MaxPoints');
SET #startingPoint := 50;
SELECT
c.id,
c.name,
DATE_FORMAT(
FROM_DAYS(DATEDIFF(CURRENT_DATE, c.age)), '%y Years %m Months %d Days') AS age,
c.photoName,
c.photoNameSmall,
(
select x.tp
from
(
SELECT t.childid,
#rn:=CASE WHEN #cid <> t.childid THEN 0 ELSE #rn+1 END AS rn,
#startingPoint + #tp:= CASE
WHEN #cid <> t.childid
THEN ifnull(t.points, 0)
ELSE (
case when #startingPoint + t.points + #tp > #maxPoints
then #maxPoints - #startingPoint
else t.points + #tp end)
END AS tp,
#cid:=t.childid AS clset,
t.timestamp
FROM
(SELECT #tp:= -1) p,
(SELECT #rn:= -1) n,
(SELECT #cid:= -1) cd,
(
SELECT r.childid, t.points, r.timestamp
FROM behaviorRatings AS r
JOIN behaviorTypes AS t ON r.behaviorID = t.behaviorTypeID
ORDER BY r.childid, r.timestamp
) t
) x
where x.childid = c.id AND Date_format(x.timestamp, '%Y-%m-%d') = Curdate()
order by x.childid, x.rn desc
limit 1
) AS totalPoints,
(
SELECT definitionName
FROM behaviorDefinitions AS d
WHERE totalPoints BETWEEN d.min AND d.max
) AS behaviorRating
FROM children AS c
Don't make things more complicated than they should be. Choose the right language for your task. In you case it's PHP:
$query = "select settingValue from settings where settingName = 'MaxPoints'";
$result = $this->db->query($query);
$row = $result->fetchAssoc();
$maxPoints = $row['settingValue'];
$query = "select * from children";
$result = $this->db->query($query);
$children = array();
while ($row = $result->fetchAssoc()) {
$row['totalPoints'] = $maxPoints;
$children[$row['id']] = $row;
}
$query = "
select c.id, coalesce(bt.points, 0) as points
from children c
join behaviorRatings br on br.childID = c.id
join behaviorTypes bt on bt.behaviorTypeID = br.behaviorID
where date(br.timestamp) = current_date()
order by c.id, br.timestamp
";
$result = $this->db->query($query);
while ($row = $result->fetchAssoc()) {
$childId = $row['id'];
$totalPoints = $children[$row['id']]['totalPoints'];
$totalPoints = $totalPoints + $row['points'];
$totalPoints = min($totalPoints, $maxPoints);
$children[$row['id']]['totalPoints'] = $totalPoints;
}
var_dump($children);
All the logic to get the total points is in the last loop. Now compare it to your query.
However - if you change the rules, allowing to exceed the limit during the day and cut the points only at the end of the day, this could be done in a single query:
select c.*, sub.totalPoints, bd.definitionName
from (
select c.id, least(100+coalesce(sum(bt.points), 0), mp.settingValue) as totalPoints
from children c
join settings mp on settingName = 'MaxPoints'
left join behaviorRatings br
on br.childID = c.id
and date(br.timestamp) = current_date()
left join behaviorTypes bt on bt.behaviorTypeID = br.behaviorID
group by c.id
) sub
join children c on c.id = sub.id
join behaviorDefinitions bd on sub.totalPoints between bd.min and bd.max
http://sqlfiddle.com/#!9/fa06c/71
While it is not a simple query, it is by far not as complex as your try. The accepded solution is doing the same ignoring the rule, that total points have to be cut to 100 every time points are gained (Sum(t.points)).
As I wrote in the comments: To follow that rule, you need some kind of iteration. There is a trick in MySQL using user variables:
select c.id, c.name, sub.totalPoints, bd.definitionName
from (
select sub.childId, sum(sub.cuttedPoints) + sp.settingValue as totalPoints
from (
select
#points := coalesce(bt.points,0) as points,
#lastTotalPoints := case when (c.id = #childId)
then #totalPoints
else sp.settingValue
end lastTotalPoints,
#totalPoints := least(#lastTotalPoints + #points, mp.settingValue) as totalPoints,
#totalPoints - #lastTotalPoints as cuttedPoints,
#childId := c.id as childId
from children c
join settings sp on sp.settingName = 'StartPoints'
join settings mp on mp.settingName = 'MaxPoints'
left join behaviorRatings br
on br.childID = c.id
and date(br.timestamp) = current_date()
left join behaviorTypes bt on bt.behaviorTypeID = br.behaviorID
cross join (select #childId := null) init_var
order by c.id, br.timestamp
) sub
join settings sp on sp.settingName = 'StartPoints'
group by sub.childId
) sub
join children c on c.id = sub.childId
join behaviorDefinitions bd on sub.totalPoints between bd.min and bd.max
Result (Brynlee behaviour: +4 -3 +4 -3):
| id | name | totalPoints | definitionName |
|----|---------|-------------|------------------------|
| 2 | Brynlee | 97 | Having an amazing day! |
| 1 | Maya | 100 | Having an amazing day! |
Brynlee gets 97 points as expected (+4 => 100, -3 => 97, +4 => 100, -3 => 97)
http://sqlfiddle.com/#!9/751c51/28
If you change the new setting "StartPoints" to 50 you will get:
| id | name | totalPoints | definitionName |
|----|---------|-------------|------------------|
| 2 | Brynlee | 52 | Not looking good |
| 1 | Maya | 50 | Not looking good |
Here Brynlee gets 52 points because the limit of 100 was never reached (+4 => 54, -3 => 51, +4 => 55, -3 => 52).
http://sqlfiddle.com/#!9/db020/13
This works because of MySQLs processing order. But this order depends on internal implementation of MySQL. This implementation may be changed in future versions without any warning. I fact - MySQL developers explicitly warn of using user variables that way.
As a general rule, other than in SET statements, you should never
assign a value to a user variable and read the value within the same
statement. For example, to increment a variable, this is okay:
SET #a = #a + 1;
For other statements, such as SELECT, you might get the results you
expect, but this is not guaranteed. In the following statement, you
might think that MySQL will evaluate #a first and then do an
assignment second:
SELECT #a, #a:=#a+1, ...;
However, the order of evaluation for expressions involving user
variables is undefined.
(User-Defined Variables)
I only use "tricks" like that for one-way reports - But never in production code.
So my suggestion is: Change the rules or use a procedural language (PHP).

SQL Server 2008 Stored Procedure returns only first column in expected results

I have the following stored procedure that I need to return multiple types of data for an annual report. For some reason I only get the first column in the results. If I comment out the NumOfBonds column, the TotalAmount column is the only one returned. I need it to return all these rows, but for some reason I am only getting one when I execute the procedure:
ALTER PROCEDURE dbo.AnnualReport
#Agency varchar(50),
#Subagency varchar(50),
#StartDate datetime,
#EndDate datetime
AS
SELECT COUNT(*) AS NumOfBonds, SUM(ISNULL(Powers.BondAmount, 0)) + SUM(ISNULL(Charges.BondAmount, 0)) AS TotalAmount,
SUM(ISNULL(Powers.BondPremium, 0)) + SUM(ISNULL(Charges.BondPremium, 0)) AS TotalPremium,
SUM(ISNULL(Powers.BondPremium, 0)) + SUM(ISNULL(Charges.BondPremium, 0)) + SUM(ISNULL(Fees.Amount, 0))
+ SUM(ISNULL(ForfeitureExpense.Amount, 0)) - SUM(ISNULL(Payment.Amount, 0)) AS TotalBalance
FROM Bond
LEFT OUTER JOIN
(
SELECT Powers.Bond, SUM(Charge.BondAmount) AS BondAmount, SUM(Charge.BondPremium) AS BondPremium
FROM Powers INNER JOIN Charge ON Powers.Surety = Charge.PowerSurety
AND Powers.PowerPrefix = Charge.PowerPrefix AND Powers.PowerNumber = Charge.PowerNumber
GROUP BY Powers.Bond
) AS Powers ON Bond.ID = Powers.Bond
LEFT OUTER JOIN
(
SELECT BondID, SUM(BondAmount) AS BondAmount, SUM(BondPremium) AS BondPremium
FROM ChargeWithoutPower
GROUP BY BondID
) AS Charges ON Bond.ID = Charges.BondID
LEFT OUTER JOIN
(
SELECT Bond, SUM(Amount) AS Amount
FROM BondFee
WHERE Date >= #StartDate AND Date <= #EndDate
GROUP BY Bond
) AS Fees ON Bond.ID = Fees.Bond
LEFT OUTER JOIN
(
SELECT Bond, SUM(Amount) AS Amount
FROM ForfeitureExpense
WHERE ExpenseDate >= #StartDate AND ExpenseDate <= #EndDate
GROUP BY Bond
) AS ForfeitureExpense ON Bond.ID = ForfeitureExpense.Bond
LEFT OUTER JOIN
(
SELECT Bond, SUM(Amount) AS Amount
FROM Payment
WHERE Date >= #StartDate AND Date <= #EndDate
GROUP BY Bond
) AS Payment ON Bond.ID = Payment.Bond
WHERE Bond.ReleaseDate >= #StartDate AND Bond.ReleaseDate <= #EndDate
AND Bond.Agency = #Agency AND Bond.Subagency = #Subagency
RETURN
The basic purpose is to give me the number of bonds written in that year, the total amount of the bonds in that year, the total premium on those bonds, and the balance at the end of the year for those bonds. I am not sure why it only sees the first column and not the rest of them.
Alright, so the basic solution here is that executing the SQL Server 2008 Stored Procedure alone did not give the proper results in Visual Studio 2010 Ultimate, but as soon as I added it to my data set and executed the procedure from C# code, it solved the problem. I'm not sure why this is, but I blame Visual Studio 2010 Ultimate.

Would using dynamic SQL + variables speed up my query?

I've realized lately that queries are much slower when I reference a variable in the filter instead of the actual value in SQL Server 2008. For example:
SELECT table_A.fruit
, SUM(table_B.units)
FROM table_A LEFT JOIN table_B
ON table_A.fruit = table_B.fruit_name
WHERE time_of_sale BETWEEN '2012-11-01' AND '2012-11-25'
is faster than
DECLARE #date1 DATE = '2012-11-01'
, #date2 DATE = '2012-11-25'
SELECT table_A.fruit
, SUM(table_B.units)
FROM table_A LEFT JOIN table_B
ON table_A.fruit = table_B.fruit_name
WHERE time_of_sale BETWEEN #date1 AND #date2
Would changing my query to this make the query as fast as the first one I posted:
DECLARE #date1 DATE = '2012-11-01'
, #date2 DATE = '2012-11-25'
DECLARE #exec VARCHAR(8000)
SELECT #exec =
'
SELECT table_A.fruit
, SUM(table_B.units)
FROM table_A LEFT JOIN table_B
ON table_A.fruit = table_B.fruit_name
WHERE time_of_sale BETWEEN ''' + #date1 + ''' AND ''' + #date2 + '''
'
EXEC(#exec)

SQL Stored Procedure fails to update data while the script in it works manually

I have a SQL Script that I execute in a job to transform tables periodically. To speed it up I put that script in a stored procedure and executed it with a job. It worked faster.
The problem occurs at times when the stored procedure even though it executes it doesn't work. I use the script manually and run it and everything works fine.
The whole script is inside a transaction and I have made it so that if some error comes up it gets logged properly. However the script doesn't give any errors.
BEGIN TRANSACTION
BEGIN TRY
-- Rounding off Campaign stats
update Campaigns
set ImpressionsBurned = ImpressionTarget
where ImpressionsBurned > ImpressionTarget and CampaignTypeID = 1
update Campaigns
set ClicksConsumed = ClickTarget
where ClicksConsumed = ClickTarget and CampaignTypeID = 2
-- Updating Campaigns & Banners
update banners
set banners.impressionsburned =
(select sum(impressionsqueue.impressionsburned) from impressionsqueue where impressionsqueue.bannerid = banners.bannerid)
where exists (select impressionsqueue.bannerid from impressionsqueue where impressionsqueue.bannerid = banners.bannerid)
update Campaigns
set ImpressionsBurned =
(select isnull(SUM(ImpressionsQueue.ImpressionsBurned),0) from ImpressionsQueue
inner join Banners on Banners.BannerID = ImpressionsQueue.BannerID and CampaignID = Campaigns.CampaignID
)
where
exists (
(select ImpressionsQueue.BannerID from ImpressionsQueue
inner join Banners on Banners.BannerID = ImpressionsQueue.BannerID and CampaignID = Campaigns.CampaignID
)
)
and
(
( Campaigns.ImpressionsBurned < Campaigns.ImpressionTarget and Campaigns.CampaignTypeID = 1)
or ( Campaigns.ClicksConsumed < Campaigns.ClickTarget and Campaigns.CampaignTypeID = 2)
or Campaigns.CampaignTypeID = 3
)
and Campaigns.IsPaused = 0
and Campaigns.StartsOn <= GetDate() and Campaigns.EndsOn >= GetDate()
-- Updating Paused Banners in the Queue
update ImpressionsQueue
set IsPaused = (
select IsPaused from Banners where Banners.BannerID = ImpressionsQueue.BannerID
)
-- Updating the Navigation URLs
update ImpressionsQueue
set NavigateURL = (
select NavigateURL from Banners where Banners.BannerID = ImpressionsQueue.BannerID
)
-- Removing any rows if the Weight of a banner is updated,
-- the banner will be reinserted later with updated impressions
delete from ImpressionsQueue
where BannerID in
(
select ImpressionsQueue.BannerID from ImpressionsQueue
inner join Banners on Banners.BannerID = ImpressionsQueue.BannerID
group by ImpressionsQueue.BannerID, Banners.Weight
having Banners.Weight <> COUNT(ImpressionsQueue.BannerID)
)
-- Removing entries whose impressions count has reached its target
delete from impressionsqueue where
BannerID in (
select Banners.BannerID from impressionsqueue
inner join Banners on banners.bannerid = impressionsqueue.bannerid
inner join campaigns on campaigns.campaignid = banners.campaignid
where Campaigns.CampaignTypeID = 1
-- excluding flat fee based campaign
group by Campaigns.ImpressionTarget, Banners.BannerID
having not (Campaigns.ImpressionTarget > sum(ImpressionsQueue.impressionsburned))
-- inverse logic for campaign count
)
-- Removing entries whose campaign click count has reached
delete from impressionsqueue where
BannerID in (
select Banners.BannerID from impressionsqueue
inner join Banners on banners.bannerid = impressionsqueue.bannerid
inner join campaigns on campaigns.campaignid = banners.campaignid and Campaigns.CampaignTypeID = 2
and Not (Campaigns.ClickTarget > Campaigns.ClicksConsumed)
-- inverse logic for campaign count
)
-- Removing entries whose campaign has expired
delete from impressionsqueue where
BannerID in (
select impressionqueueid from impressionsqueue
inner join Banners on banners.bannerid = impressionsqueue.bannerid
inner join campaigns on campaigns.campaignid = banners.campaignid
and not (Campaigns.StartsOn <= GETDATE() and Campaigns.EndsOn >= GETDATE())
-- inverse logic for date
)
----------------------------------------------------------------------------------------
-- Begin updating Impressions Queue
----------------------------------------------------------------------------------------
Declare #TempBanners Table(BcID [int] IDENTITY(1,1),ZoneID [int], BannerID [int], Weight [int], FileID [uniqueidentifier], IsPaused [bit], Impressions [int], URL [nvarchar](2048))
/*
Insert into the temp table all the banners that:
1) Belong to an active campaign => c.StartsOn <= GetDate() and c.EndsOn >= GetDate()
2) and Belong to a campaign that is not paused
3) and The banner itself is not paused
4) and Flat Fee campaign banner
*/
Insert Into #TempBanners (ZoneID, BannerID, Weight, FileID, IsPaused, Impressions, URL)
Select
bz.ZoneID,
b.BannerID,
b.Weight,
b.FileID,
b.IsPaused,
b.ImpressionsBurned,
b.NavigateURL
From Banners b
Join Bannerzones bz on b.BannerID = bz.BannerID
Join Campaigns c on b.CampaignID = c.CampaignID
And c.StartsOn <= GetDate() and c.EndsOn >= GetDate()
And c.IsPaused = 0
And b.IsPaused = 0
And (
(c.CampaignTypeID = 1 And c.ImpressionsBurned < c.ImpressionTarget)
Or (c.CampaignTypeID = 2 And c.clicksconsumed < c.clicktarget)
Or (c.campaigntypeid = 3)
);
-- Declaration of Vairables
Declare #index As int,#maxRow As int, #weight Int, #bcid int
Set #index = 1 --Because we will start from First row
Select #maxRow = Count(0) From #TempBanners Where Weight > 1
-- How many rows we have that has weight more then 1
While(#index <= #maxRow)
Begin
Select
#weight = V.Weight,
#bcid = V.BcID
From (
Select
BCid,
Weight,
ROW_NUMBER() Over (Order By Bcid Asc) Row
From #TempBanners
Where Weight > 1
)V
Where V.Row = #index
Set #index = #index + 1
While(#weight <> 1)
Begin
Insert Into #TempBanners (ZoneID, BannerID, Weight, FileID, URL)
Select ZoneID, BannerID, Weight, FileID, URL From #TempBanners Where BcID = #bcid
set #weight = #weight - 1
End
End
-- INSERT INTO THE IMPRESSION QUEUE ALL THE BANNERS THAT ARE NOT YET IN THE QUEUE
Insert Into ImpressionsQueue (BannerID, ZoneID, FileID, ImpressionsBurned, RowUpdated, IsPaused, NavigateURL )
Select V.BannerID, V.ZoneID, V.FileID, V.Impressions, GETDATE(), V.IsPaused, V.URL
From
(
Select m.BannerID, m.ZoneID, m.FileID,
isnull(m.IsPaused,0) as IsPaused,
isnull(m.Impressions,0) as Impressions,
ISNULL(m.URL,'') as URL
From #TempBanners m
where Weight >
(select COUNT(t.bannerid)
from ImpressionsQueue as t
where t.BannerID = m.BannerID
and t.FileID = m.FileID
and t.ZoneID = m.ZoneID
)
)As V;
-- Update the banner file id in case it is modified after the banner was created
Update ImpressionsQueue
Set FileID = CTE.FileID, ImpressionsQueue.IsPaused = isnull(CTE.IsPaused,0), ImpressionsQueue.NavigateURL = CTE.URL
From ImpressionsQueue I
Inner Join #TempBanners As CTE On CTE.BannerID = I.BannerID And CTE.ZoneID = I.ZoneID --And CTE.FileID <> I.FileID
----------------------------------------------------------------------------------------
-- End updating Impressions Queue
----------------------------------------------------------------------------------------
END TRY
BEGIN CATCH
declare #error varchar(3000) = 'Message: ' + ERROR_MESSAGE() + ' ' + ERROR_LINE()
exec master.sys.xp_logevent 50001, #error , 'Warning'
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION
END CATCH
IF ##TRANCOUNT > 0
COMMIT TRANSACTION
Not sure if that's the cause of all problem - but if I were you, I'd put the COMMIT TRANSACTION inside the TRY..... block:
-------------------------------------------------------------------------------
-- End updating Impressions Queue
-------------------------------------------------------------------------------
IF ##TRANCOUNT > 0
COMMIT TRANSACTION
END TRY
BEGIN CATCH
declare #error varchar(3000) = 'Message: ' + ERROR_MESSAGE() + ' ' + ERROR_LINE()
exec master.sys.xp_logevent 50001, #error , 'Warning'
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION
END CATCH
If everything goes okay, you'll execute COMMIT TRANSACTION as the last statement of your TRY... block - and if something blows up, you'll fall into the CATCH block anyway. Might be dangerous to call COMMIT TRANSACTION outside your CATCH block after it....