SQL Server, Having Clause, Where, Aggregate Functions - sql-server

In my problem which I am trying to solve, there is a performance values table:
Staff PerformanceID Date Percentage
--------------------------------------------------
StaffName1 1 2/15/2016 95
StaffName1 2 2/15/2016 95
StaffName1 1 2/22/2016 100
...
StaffName2 1 2/15/2016 100
StaffName2 2 2/15/2016 100
StaffName2 1 2/22/2016 100
And the SQL statement as follows:
SELECT TOP (10)
tbl_Staff.StaffName,
ROUND(AVG(tbl_StaffPerformancesValues.Percentage), 0) AS AverageRating
FROM
tbl_Staff
INNER JOIN
tbl_AcademicTermsStaff ON tbl_Staff.StaffID = tbl_AcademicTermsStaff.StaffID
INNER JOIN
tbl_StaffPerformancesValues ON tbl_AcademicTermsStaff.StaffID = tbl_StaffPerformancesValues.StaffID
WHERE
(tbl_StaffPerformancesValues.Date >= #DateFrom)
AND (tbl_AcademicTermsStaff.SchoolCode = #SchoolCode)
AND (tbl_AcademicTermsStaff.AcademicTermID = #AcademicTermID)
GROUP BY
tbl_Staff.StaffName
ORDER BY
AverageRating DESC, tbl_Staff.StaffName
What I am trying to do is, from a given date, for instance 02-22-2016,
I want to calculate average performance for each staff member.
The code above gives me average without considering the date filter.
Thank you.

Apart from your join conditions and table names which looks quite complex, One simple question, If you want the results for a particular date then why is the need of having
WHERE tbl_StaffPerformancesValues.Date >= #DateFrom
As you said your query is displaying average results but not for a date instance. Change the above line to WHERE tbl_StaffPerformancesValues.Date = #DateFrom.
Correct me if I am wrong.

Thanks for the replies, the code above, as you all say and as it is also expected is correct.
I intended to have a date filter to see the results from the given date until now.
The code
WHERE tbl_StaffPerformancesValues.Date >= #DateFrom
is correct.
The mistake i found from my coding is, in another block i had the following:
Protected Sub TextBoxDateFrom_Text(sender As Object, e As System.EventArgs) Handles TextBoxDate.PreRender, TextBoxDate.TextChanged
Try
Dim strDate As String = Date.Parse(DatesOfWeekISO8601(2016, WeekOfYearISO8601(Date.Today))).AddDays(-7).ToString("dd/MM/yyyy")
If Not IsPostBack Then
TextBoxDate.Text = strDate
End If
SqlDataSourcePerformances.SelectParameters("DateFrom").DefaultValue = Date.Parse(TextBoxDate.Text, CultureInfo.CreateSpecificCulture("id-ID")).AddDays(-7)
GridViewPerformances.DataBind()
Catch ex As Exception
End Try
End Sub
I, unintentionally, applied .AddDays(-7) twice.
I just noticed it and removed the second .AddDays(-7) from my code.
SqlDataSourcePerformances.SelectParameters("DateFrom").DefaultValue = Date.Parse(TextBoxDate.Text, CultureInfo.CreateSpecificCulture("id-ID"))
Because of that mistake, the SQL code was getting the performance values 14 days before until now. So the average was wrong.
Thanks again.

Related

Calculate days in between certain events based on multiple conditions

I am curious if one of you guys can help me to calculate how much days (DAYS BETWEEN TravelStart AND TravelEnd) a certain boat BoatID has been used ONLY for luxury tours BoutTourID = Luxury by different captains CaptainID,
and now for the weird part: UNTIL the next Standard tour BoutTourID = Standard starts. I don't want to take the Cancelled trips into account Status = Cancelled.
CaptainID BoatID BoatTourID Status TravelStart TravelEnd
Jack AlphaBoat Standard 1-7-2019 20-7-2019
Kevin AlphaBoat Luxury 21-7-2019 31-7-2019
Eric AlphaBoat Luxury Cancelled 1-8-2019 10-8-2019
Nick AlphaBoat Standard 11-8-2019 20-8-2019
John AlphaBoat Luxury 21-8-2019 30-8-2019
Lionel BigBoat Standard 1-8-2019 20-8-2019
Jeffrey BigBoat Luxury 20-8-2019 25-8-2019
Chris BigBoat Standard 26-8-2019 28-8-2019
This in SQL should give the following results, so in the basis the table shows the exact same amount of records:
CaptainID
Jack 0 --since BoatTourID = Standard, it should not be calculated
Kevin 10
Eric 0 --since Status = Cancelled
Nick 0
John 9
Lionel 19
Jeffrey 5
Chris 2
It should be possible to run it in 1 SQL query.
The code I wrote so far is very messy and doesn't come close to solving it, so I rather not post it, since I hope for a fresh idea. In case I will still post it, if necessary!
The following query should do what you want:
SELECT
CaptainID
,CASE WHEN BoatTourID = 'Standard' OR [Status] = 'Cancelled' THEN 0
ELSE DATEDIFF(DAY,TravelStart,TravelEnd) AS [Date Difference]
FROM YourTable
You can achieve it by CASE expression along with group by. You can add additional columns in select and group by clause upon your requirement
select CaptinID,
DATEDIFF( DAY,
MIN (CASE WHEN
BoutTourID = 'Luxury' and NOT [Status] = 'Cancelled'
THEN TravelStart Else cast( GETDATE() as date ) ),
MAX (CASE WHEN
BoutTourID = 'Luxury' and NOT [Status] = 'Cancelled'
THEN TravelEnd Else cast ( GETDATE() as date ) )
) Duration_Days
from yourtbale
Group by CaptinID
MIN, MAX and Group by would help you get one line per CaptinID duration from whole trips. In case whole trips per captin not a requirement, you can change remove group by just use CASE expression accordingly..

Update query failed '0' rows affected

I am trying to run this query but the query keeps giving up on me:
Update StockInvoiceInfo set Quantity = Quantity - 2 where p_id = 5 AND ProductDate = convert(Cast('31-5-2015' as datetime)) ;
After Running this code it returns an error below:
Incorrect syntax near '31-5-2015'
The datatype of the ProductDate column isDate. I am using Sql Server 2012.
You have used Convert functions but didn't supplied it with parameters. Also there is no need for this function here. Also take care of date format. I have changed it to standard format:
Update StockInvoiceInfo set Quantity = Quantity - 2
where p_id = 5 AND ProductDate = Cast('2015-05-31' as datetime)
If all you are trying to do is compare a Sql Date, then just use an agnostic format like '20150531' or easier to read '2015-05-31'. No need for casts or convert at all, i.e.
WHERE ... AND ProductDate = '2015-05-31'
However, if ProductDate isn't a date, but one of the *DATETIME* data types, and you are looking to update any time on the same day, then I believe you are looking for something like:
Update StockInvoiceInfo
set Quantity = Quantity - 2
where
p_id = 5
AND CAST(ProductDate AS DATE) = '2015-05-31';
However, the performance will be lousy as the clause isn't likely to be SARGable. You're better off simply doing:
AND ProductDate >= '2015-05-31' AND ProductDate < '2015-06-01';
(Resist the temptation to use between, or hacks like ':23:59:59' as there will be data corner cases which will bite you)
use CAST('5-31-2015' as DATETIME)
with the above update statement you started convert but with incomplete syntax
here the convert syntax
Update StockInvoiceInfo
set Quantity = Quantity - 2
where p_id = 5
AND ProductDate = convert(datetime,Cast('31-5-2015' as varchar),103) ;

SQL Server LEFT JOIN

This query has been keeping me busy for the last couple of days. I tried to rewrite it with different ideas but I keep having the same problem. To simplify the problem I put part of my query in a view, this view returns 23 records. Using a left join I would like to add fields coming from the table tblDatPositionsCalc to these 23 records. As you can see I have an additional condition on the tblDatPositionsCalc in order to only consider the most recent records. With this condition it would return 21 records. The join should be on two fields together colAccount and colId.
I simply want the query to return the 23 records from the view and where possible have the information from tblDatPositionsCalc. There is actually only 2 records in the view without corresponding id and account in tblDatPositionsCalc, that means out of the 23 records only 2 will have missing values in the fields coming from the table tblDatPositionsCalc.
The problem with my query is that it only returns the 21 records from tblDatPositionsCalc. I don't understand why. I tried to move the condition on date in just after the JOIN condition but that did not help.
SELECT TOP (100) PERCENT
dbo.vwCurrPos.Account,
dbo.vwCurrPos.Id,
dbo.vwCurrPos.TickerBB,
dbo.vwCurrPos.colEquityCode,
dbo.vwCurrPos.colType,
dbo.vwCurrPos.colCcy,
dbo.vwCurrPos.colRegion,
dbo.vwCurrPos.colExchange,
dbo.vwCurrPos.[Instr Type],
dbo.vwCurrPos.colMinLastDay,
dbo.vwCurrPos.colTimeShift,
dbo.vwCurrPos.Strike,
dbo.vwCurrPos.colMultiplier,
dbo.vwCurrPos.colBetaVol,
dbo.vwCurrPos.colBetaEq,
dbo.vwCurrPos.colBetaFloor,
dbo.vwCurrPos.colBetaCurv,
dbo.vwCurrPos.colUndlVol,
dbo.vwCurrPos.colUndlEq,
dbo.vwCurrPos.colUndlFut,
tblDatPositionsCalc_1.colLots,
dbo.vwCurrPos.[Open Positions],
dbo.vwCurrPos.colListMatShift,
dbo.vwCurrPos.colStartTime,
tblDatPositionsCalc_1.colPrice,
tblDatPositionsCalc_1.colMktPrice,
dbo.vwCurrPos.colProduct,
dbo.vwCurrPos.colCalendar,
CAST(dbo.vwCurrPos.colExpiry AS DATETIME) AS colExpiry,
dbo.vwCurrPos.colEndTime,
CAST(tblDatPositionsCalc_1.colDate AS datetime) AS colDate,
dbo.vwCurrPos.colFund,
dbo.vwCurrPos.colExchangeTT,
dbo.vwCurrPos.colUserTag
FROM dbo.vwCurrPos
LEFT OUTER JOIN dbo.tblDatPositionsCalc AS tblDatPositionsCalc_1
ON tblDatPositionsCalc_1.colId = dbo.vwCurrPos.Id
AND tblDatPositionsCalc_1.colAccount = dbo.vwCurrPos.Account
WHERE (tblDatPositionsCalc_1.colDate =
(SELECT MAX(colDate) AS Expr1 FROM dbo.tblDatPositionsCalc))
ORDER BY
dbo.vwCurrPos.Account,
dbo.vwCurrPos.Id,
dbo.vwCurrPos.colEquityCode,
dbo.vwCurrPos.colRegion
Any idea what might cause the problem?
(Option 1) DrCopyPaste is right so your from clause would look like:
...
FROM dbo.vwCurrPos
LEFT OUTER JOIN dbo.tblDatPositionsCalc AS tblDatPositionsCalc_1
ON tblDatPositionsCalc_1.colId = dbo.vwCurrPos.Id
AND tblDatPositionsCalc_1.colAccount = dbo.vwCurrPos.Account
and (tblDatPositionsCalc_1.colDate =
(SELECT MAX(colDate) AS Expr1 FROM dbo.tblDatPositionsCalc))
...
reason: the where clause restriction of left joined to column = some expression with fail to return for "null = something" so the row will be removed.
(Option 2) As oppose to pushing code in to additional views where it is harder to maintain you can nest sql select statements;
select
X.x1,X.x2,
Y.*
from X
left join
(select Z.z1 as y1, Z.z2 as y2, Z.z3 as y3
from Z
where Z.z1 = (select max(Z.z1) from Z)
) as Y
on x.x1 = Y.y1 and X.x2 = Y.y2
The advantage here is you check each nested sub query a move out quickly. Although if you still building up more logic check out common table expressions (CTE's) http://msdn.microsoft.com/en-us/library/ms175972.aspx

Yet another subquery issue

Hello from an absolute beginner in SQL!
I have a field I want to populate based on another table. For this I have written this query, which fails with: Msg 512, Level 16, State 1, Line 1
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
The statement has been terminated.
oK, here goes:
Update kre.CustomerOrderLineCopy
SET DepNo = (SELECT customerordercopy.DepNo
FROM kre.CustomerOrderCopy , kre.CustomerOrderLineCopy
WHERE CustomerOrderLineCopy.OrderCopyNo =kre.CustomerOrderCopy.OrderCopyNo)
WHERE CustomerOrderLineCopy.OrderCopyNo = (SELECT CustomerOrderCopy.OrderCopyNo
FROM kre.CustomerOrderCopy, kre.CustomerOrderLineCopy
WHERE kre.CustomerOrderLineCopy.OrderCopyNo = kre.CustomerOrderCopy.OrderCopyNo)
What I'm trying to do is to change DepNo in CustomerOrderLineCopy, with the value in DepNo in CustomerOrderCopy - based on the same OrderCopyNo in both tables.
I'm open for all suggestion.
Thanks,
ohalvors
If you just join the tables together the update is easier:
UPDATE A SET A.DepNo = B.DepNo
FROM kre.CustomerOrderLineCopy A
INNER JOIN kre.CustomerOrderCopy B ON A.OrderCopyNo = B.OrderCopyNo
The problem is that at least one of your sub queries return more than one value. Think about this:
tablePerson(name, age)
Adam, 11
Eva, 11
Sven 22
update tablePerson
set name = (select name from tablePerson where age = 11)
where name = 'Sven'
Which is equivalent to: set Sven's name to Adam and Eva. Which is not possible.
If you want to use sub queries, either make sure your sub queries can only return one value or force one value by using:
select top 1 xxx from ...
This may be enough to quieten it down:
Update kre.CustomerOrderLineCopy
SET DepNo = (SELECT customerordercopy.DepNo
FROM kre.CustomerOrderCopy --, kre.CustomerOrderLineCopy
WHERE CustomerOrderLineCopy.OrderCopyNo =kre.CustomerOrderCopy.OrderCopyNo)
WHERE CustomerOrderLineCopy.OrderCopyNo = (SELECT CustomerOrderCopy.OrderCopyNo
FROM kre.CustomerOrderCopy --, kre.CustomerOrderLineCopy
WHERE kre.CustomerOrderLineCopy.OrderCopyNo = kre.CustomerOrderCopy.OrderCopyNo)
(Where I've commented out kre.CustomerOrderLineCopy in the subqueries) That is, you were hopefully trying to correlate these subqueries with the outer table - not introduce another instance of kre.CustomerOrderLineCopy.
If you still get an error, then you still have multiple rows in kre.CustomerOrderCopy which have the same OrderCopyNo. If that's so, you need to give us (and SQL Server) the rules that you want to apply for how to select which row you want to use.
The danger of switching to the FROM ... JOIN form shown in #Avitus's answer is that it will no longer report if there are multiple matching rows - it will just silently pick one of them - which one is never made clear.
Now I look at the query again, I'm not sure it even needs a WHERE clause now. I think this is the same:
Update kre.CustomerOrderLineCopy
SET DepNo = (
SELECT customerordercopy.DepNo
FROM kre.CustomerOrderCopy
WHERE CustomerOrderLineCopy.OrderCopyNo = kre.CustomerOrderCopy.OrderCopyNo)

Dynamic column value with group by (sql server and Linq)

i have a table Plan with following sample data
i want to aggregate the result by PlanMonth and for PlanStatus i want that if any of its (in a group) values is Drafted i get drafted in the result and Under Approval otherwise. i have done it using following query
select PlanMonth, case when Flag=1 then 'Drafted' else 'Under Approval' end as PlanStatus
from
(select p.PlanMonth, Max(CASE WHEN p.PlanStatus = 'Drafted' THEN 1 ELSE 0 END) Flag
from Plans p
group by p.PlanMonth
) inquery
i have consulted this blog post. Is there something wrong with it? Moreover, if someone can help me translate it to linq i will be grateful
The query you have will work.
With the sample data you have provided it can be simplified a bit.
select p.PlanMonth,
min(p.PlanStatus) as PlanStatus
from Plans as p
group by p.PlanMonth
This will not work if you have values in PlanStatus that is alphabetically sorted before Drafted.
Following Linq query worked for me
return (from p in db.mktDrVisitPlans
group p by p.PlanMonth into grop
select
new VMVisitPlan
{
PlanMonth = grop.Key
PlanStatus = grop.Any(x=>x.p.PlanStatus == "Drafted")?"Hold":"Under Approval",
}).ToList();

Resources