SQL Server Update with Case involving another table - sql

I have 2 tables. One has order elements (OE) and one has project information(PO). There are many order elements to 1 project. The way the tables are set up, the project date is is in the PO and the Currency is in the OE. I need to update the Euro Exchange rate in the OE table. I am trying to do something like this
UPDATE [OETest]
SET [Euro Exchange Rate] = {
CASE
WHEN (DATEPART(month, PO.[Project Date Time]) = January)
THEN 8.143296
WHEN (DATEPART(month, PO.[Project Date Time]) = February)
THEN 8.340111
}
FROM [POTest] PO, [OETest] OE
WHERE OE.[Currency] = 'YUAN'
But I am lost (This is one of many queries I have tried). Can anyone help me construct the necessary query and talk me through why it works?
This particular query is telling me there is Incorrect syntax near keyword CASE
To make it more clear what I am trying to accomplish: I have a column for the euro exchange rate in the OE table. I have the average monthly exchange rate that I obtained from a website (not in the table). I want to set this exchange rate column based on the month of the project and the currency. I am going to handle each currency in separate queries so the Yuan is the only currency I'm worried about for this query. The month is in the PO table. I need to use the month from the PO table in the case statement.

UPDATE OE -- the alias here rather than the base table name
SET [Euro Exchange Rate] = 8.143296
FROM [POTest] PO
JOIN [OETest] OE ON OE.project_id = PO.project_id -- you need a link
WHERE OE.[Currency] = 'YUAN'
-- the following date range represents January this year
AND PO.[Project Date Time] >= '20120101'
AND PO.[Project Date Time] < '20120201'
You only need a case statement if you need different values depending on different dates
UPDATE OE -- the alias here rather than the base table name
SET [Euro Exchange Rate] =
CASE Month(PO.[Project Date Time])
when 1 then 8.143296
when 2 then 7.143296
when 3 then 7.743296
END
FROM [POTest] PO
JOIN [OETest] OE ON OE.project_id = PO.project_id -- you need a link
WHERE OE.[Currency] = 'YUAN'
-- the following date range represents 3 months this year
AND PO.[Project Date Time] >= '20120101'
AND PO.[Project Date Time] < '20120401'

What exactly seems to be the problem?
I can see many problems with the query. What are the sql errors you are getting?
IN any case, if I was to try to do the same as what i 'think' you are doing, I would do this:
UPDATE [OETest] OE
SET [Euro Exchange Rate] =
(SELECT CASE WHEN (DATEPART(month, PO.[Project Date Time]) = 'January')
THEN 8.143296
ELSE 0.000000
END ExchageRate
FROM [POTest] PO)
WHERE OE.[Currency] = 'YUAN'
What I am trying to do here is to select the result I want after the SET block. In the CASE statement, I have added an else in the event that I dont get a result from the date part.
The WHERE part is should be a WHERE condition on the UPDATE clause as you need to tell it what records you want to update, unless you want to update all records in that OETest table.
So in summary you are saying
Update the Euro Exchange Rate field with the value from the POTest Table when the month part of the Project Date Time field is equal to January, and update records in the OETest table where the Currency value is 'YUAN'.
Note, that you might need to have a WHERE clause in the SELECT statement as it might return multiple records and you only want one is order to get the Project Date Time field. At a guess, you might want to add a where statement such as follows:
UPDATE [OETest] OE
SET [Euro Exchange Rate] =
(SELECT CASE WHEN (DATEPART(month, PO.[Project Date Time]) = 'January')
THEN 8.143296
ELSE 0.000000
END ExchageRate
FROM [POTest] PO WHERE PO.ProjectID = 100)
WHERE OE.[Currency] = 'YUAN'
Let me know if this helps.
Regards
JT

Related

SQL Query to pull date range based on dates in a table

I have some SQL code which is contained in an SSRS report and when run pulls a list of student detentions for a set period such as a week or month but I have been asked to get the report to run automatically from the start of the current school term to the date the report has been run. Is this possible? We have 3 terms per year and the dates change each year. The report has multiple subscriptions which will run weekly and filter to students in particular day houses and years so we ideally need the report to update itself.
We have a table in our database titled TblSchoolManagementTermDates which includes txtStartDate and txtFinishDate columns for each term.
The date of the detention is stored in the column detPpl.dDetentionDate
The full SQL code I am currently using is:
SELECT ppl.txtSchoolID AS SchoolID,
detPpl.TblDisciplineManagerDetentionsPupilsID AS DetentionID,
ppl.txtSurname AS Surname,
ppl.txtForename AS Forename,
ppl.txtPrename AS PreferredName,
ppl.intNCYear AS Year,
ppl.txtAcademicHouse AS House,
schTermDates.intSchoolYear AS AcademicYear,
schTerms.txtName AS TermName,
CAST(schTermDates.intSchoolYear AS CHAR(4)) + '/' +
RIGHT(CAST(schTermDates.intSchoolYear + 1 AS CHAR(4)), 2) AS AcademicYearName,
detPpl.dDetentionDate AS DetentionDate,
detSessions.txtSessionName AS DetentionName,
detPpl.txtOffenceDescription AS OffenceDescription,
LEFT(Staff.Firstname, 1) + '. ' + Staff.Surname AS PutInBy,
detPpl.intPresent AS AttendedDetention
FROM dbo.TblPupilManagementPupils AS ppl
INNER JOIN
dbo.TblDisciplineManagerDetentionsPupils AS detPpl
ON detPpl.txtSchoolID = ppl.txtSchoolID
INNER JOIN
dbo.TblDisciplineManagerDetentionsSessions AS detSessions
ON detPpl.intDetentionSessionID = detSessions.TblDisciplineManagerDetentionsSessionsID
INNER JOIN
dbo.TblStaff AS Staff
ON Staff.User_Code = detPpl.txtSubmittedBy
INNER JOIN
dbo.TblSchoolManagementTermDates AS schTermDates
ON detPpl.dDetentionDate BETWEEN schTermDates.txtStartDate AND schTermDates.txtFinishDate
INNER JOIN
dbo.TblSchoolManagementTermNames AS schTerms
ON schTermDates.intTerm = schTerms.TblSchoolManagementTermNamesID
LEFT OUTER JOIN
dbo.TblDisciplineManagerDetentionsCancellations AS Cancelled
ON Cancelled.intSessionID = detPpl.intDetentionSessionID
AND Cancelled.dDetDate = detPpl.dDetentionDate
WHERE (ppl.txtAcademicHouse = 'Challoner') AND (Cancelled.TblDisciplineManagerDetentionsCancellationsID IS NULL) AND (CAST(detPpl.dDetentionDate AS DATE) >= CAST (GETDATE()-28 AS DATE))
ORDER BY ppl.txtSurname, ppl.txtForename, detPpl.dDetentionDate
What you need is to assign a couple of parameters to this code.
lets call the parameters
#term_start
and
#term_end
In your where clause you simply need to remove this piece
AND (CAST(detPpl.dDetentionDate AS DATE) >= CAST (GETDATE()-28 AS DATE))
and add this piece in
AND (CAST(detPpl.dDetentionDate AS DATE) between #term_start and #term_end
Now create another dataset based on your term dates - lets call the dataset term_dates
something like this (I'm making up these fields as I don't know what columns are available or have no sample data) Use the idea below to adapt to your requirements
select
min(term_start_date) as start_date
,max(term_end_date) as end_date
from TblSchoolManagementTermNames
where convert(date,getdate()) between term_start_date and term_end_date
Now your report should have 2 parameters.. You simply need to set the default value for the parameters.
Set the default value for #term_start as the start_date and #term_end as the end_date from your term_dates dataset
Run your report.. You should have the data between the term dates.
This should work.. unless I've misunderstood the requirement

How to find if there is a match in a certain time interval between two different date fields SQL?

I have a column in my fact table that defines whether a Supplier is old or new based on the following case-statement:
CASE
WHEN (SUBSTRING([Reg date], 1, 6) = SUBSTRING([Invoice date], 1, 6)
THEN ('New supplier')
ELSE('Old supplier')
END as [Old/New supplier]
So for example, if a Supplier was registered 201910 and Invoice date was 201910 then the Supplier would be considered a 'New supplier' that month. Now I want to calculate the number of Old/New suppliers for each month by doing an distinct count on Supplier no, which is not a problem. The last step is where it gets tricky, now I want to count the number of New/Old suppliers over a 12-month period(if there has been a match on Invoice date and reg date in any of the lagging 12 months). So I create the following mdx expression:
aggregate(parallelperiod([D Time].[Year-Month-Day].[Year],1,[D Time].[Year-Month-Day].currentmember).lead(1) : [D Time].[Year-Month-Day].currentmember ,[Measures].[Supplier No Distinct Count])
The issue I am facing is that it will count Supplier no "1234" twice since it has been both new and old during that time period. What I wish is that, if it finds one match it would be considered a "New" Supplier for that 12- month period.
This is how the result ends up looking but I want it to be zero for "Old" since Reg date and Invoice date matched once during that 12-month period it should be considered new for the whole Rolling 12 month on 201910
Any help, possible approaches or ideas are highly appreciated.
Best regards,
Rubrix
Aggregate first at the supplier level and then at the type level:
select type, count(*)
from (select supplierid,
(case when min(substring(regdate, 1, 6)) = min(substring(invoicedate, 1, 6))
then 'new' else 'old'
end) as type
from t
group by supplierid
) s
group by type;
Note: I assume your date columns are in some obscure string format for your code to work. Otherwise, you should be using appropriate date functions.
SELECT COUNT(*) OVER () AS TotalCount
FROM Facts
WHERE Regdate BETWEEN(olddate, newdate) OR InvoiceDate BETWEEN(olddate, newdate)
GROUP BY
Supplier
The above query will return all the suppliers within that time period and then group them. Thus COUNT(*) will only include unique subscribers.
You might wanna change the WHERE clause because I didn't quite understand how you are getting the 12 month period. Generally if your where clause returns the suppliers within that time period(they don't have to be unique) then the group by and count will handle the rest.

SQL case expression to run report based on Fiscal Year

I'm attempting to create some reports in my organization's new Help Desk system, which uses sql for its database and reporting systems. I've never interacted with sql before, so I'm having to make this up as I go. I've been able to cannibalize most of what I need from other, pre-made reports, but I'm running into a road block getting the report to group by Fiscal Year and not Calendar Year. The report I'm currently working on is meant to calculate the average time to closure on tickets. The original version grouped and ordered everything by the calendar year, and appeared to be working. However, when I try to retrofit the code to group/sort based on a July 1-June 30 Fiscal Year using the suggested method in this answer (as shown in my report code below), I'm getting the error, "The multi-part identifier "htblticket.date could not be bound."
I also tried some variants on this answer, with even less success. Does anyone have some suggestions on what I might be screwing up here, or some ideas on better ways to approach this? I'd appreciate any help/enlightenment you can provide!
Select Top 1000000 Case
When DatePart(mm, htblticket.date) > 6 Then DatePart(yyyy, htblticket.date)
+ 1
Else DatePart(yyyy, htlbticket.date)
End As [Fiscal Year],
Convert(Decimal(9,2),Avg(Cast(DateDiff(ss, htblticket.date,
ClosedDate.CloseDate) As decimal) / 86400)) As AverageDays
From htblticket
Inner Join (Select Top 1000000 htblticket.ticketid,
Max(htblhistory.date) As CloseDate
From htblticket
Inner Join htblticketstates On htblticketstates.ticketstateid =
htblticket.ticketstateid
Inner Join htblhistory On htblhistory.ticketid = htblticket.ticketid
Inner Join htblticketstates htblticketstates1 On
htblhistory.ticketstateid = htblticketstates1.ticketstateid
Inner Join htblhistorytypes On htblhistorytypes.typeid =
htblhistory.typeid
Where htblticketstates.statename = 'Closed' And
htblticketstates1.statename = 'Closed' And
htblhistorytypes.name In ('Status changed',
'Note added and state changed', 'Internal note added and state changed')
Group By htblticket.ticketid) As ClosedDate On ClosedDate.ticketid =
htblticket.ticketid
Group By Case
When DatePart(mm, htblticket.date) > 6 Then DatePart(yyyy, htblticket.date)
+ 1
Else DatePart(yyyy, htlbticket.date)
End
Order By [Fiscal Year] Desc
Your question boils down to how to group by the (Australian) financial year July-June.
One simple approach would be to create a column “financial_year_start” which is an expression that subtracts 6 months from each date and extracts the year of the result, then group by that.

Update column when datediff is greater then other column in the same table

I'm struggling with my school assignment, where I have to update a table column based on the difference between two dates. If the difference is lower or equal than column 'maturity' in the table, I had to set column 'Payment' to 'PaymentOK', if the difference is greater than 'maturity', the 'Payment' has to be set to 'Bilker'.
I've tried
#IFNOTFieldExists(TableName=Invoices;FieldName=Payment;)
Alter table Invoices ADD COLUMN Payment TEXT
GO
UPDATE Invoices SET Payment = CASE
WHEN DATEDIFF (Day, Datum, ZaplateneDna) <= Maturity
THEN 'PaymentOK'
ELSE 'Bilker'
END
#ENDIF
Been trying IF THEN statements, UPDATE WHEN CASE statements but I'm still getting syntax errors.
I'm a bit new in sql and I'm unable to combine UPDATE column1 IF DATEDIFF is <= or > then SET Column2 to (based on the <> sign).
Any ideas or advices please?
Thank you in advance, much appreciated.
UPDATE Invoices
SET Payment = CASE
WHEN DATEDIFF(DAY, [Date], DateOfPayment) <= Maturity
THEN 'PaymentOK'
ELSE 'Bilker'
END

join two tables to get tomorrow's price (and the price two days from "now")

I'm trying to do a JOIN query to analyze some stocks. In my first table called top10perday, I list 10 stocks per day that I have chosen to "buy" the next day and sell the following day:
date symbol
07-Aug-08 PM
07-Aug-08 HNZ
07-Aug-08 KFT
07-Aug-08 MET
...
08-Aug-08 WYE
08-Aug-08 XOM
08-Aug-08 SGP
08-Aug-08 JNJ
For instance, for record #1:
the date of the record is 07-Aug-08
I want to buy a share of PM stock on the next trading day after 07-Aug-08 (which is 08-Aug-08)
I want to sell that shar eof PM stock two trading days after 07-Aug-08), which turns out to be 11-Aug-08
My stock prices are in a table called prices, which looks like this:
date symbol price
07-Aug-08 PM 54.64
08-Aug-08 PM 55.21
11-Aug-08 PM 55.75
12-Aug-08 PM 55.95
... many more records with trading day, symbol, price
I want to do a JOIN so that my result set looks like this:
date symbol price-next-day price-two-days
07-Aug-08 PM 55.21 55.75
...
list one record per date and symbol in table1.
I have tried doing something like:
SELECT top10perday.date, top10perday.symbol, Min(prices.date) AS MinOfdate
FROM prices INNER JOIN top10perday ON prices.symbol = top10perday.symbol
GROUP BY top10perday.date, top10perday.symbol
HAVING (((Min(prices.date))>[date]));
I have tried many variations of this, but I'm clearly not on the right path, because the result set just includes 10 rows as of the earliest date shown in my top10perday table.
I am using Microsoft Access. Thanks in advance for your help! :-)
This syntax worked in Access 2003:
SELECT t10.Date, t10.Symbol, p1.date, p1.price, p2.date, p2.price
FROM
(top10perday AS t10
LEFT JOIN prices AS p1
ON t10.Symbol = p1.symbol)
INNER JOIN prices AS p2 ON t10.Symbol = p2.symbol
WHERE (
((p1.date)=((Select Min([date]) as md
from prices
where [date]>t10.[Date] and symbol = t10.symbol
))
) AND ((p2.date)=((Select Min([date]) as md
from prices
where [date]>p1.[Date] and symbol = t10.symbol)
))
);
the idea is to get the first (min) date that is greater than the date in the previous table (top10perday and the prices as p1)
This should just be a join between three copies of the prices table. The problem is that you need to join to the next trading day, and that's a slightly trickier problem, since it's not always the next day. So we end up with a more complex situation (particularly as some days are skipped beacuse of holidays).
If it weren't Access you could use row_number() to order your prices by date (using a different sequence per stock code).
WITH OrderedPrices AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY symbol ORDER BY date) AS RowNum
FROM Prices
)
SELECT orig.*, next_day.price, two_days.price
FROM OrderedPrices orig
JOIN
OrderedPrices next_day
ON next_day.symbol = orig.symbol AND next_day.RowNum = orig.RowNum + 1
JOIN
OrderedPrices two_days
ON two_days.symbol = orig.symbol AND two_days.RowNum = orig.RowNum + 2
;
But you're using Access, so I don't think you have ROW_NUMBER().
Instead, you could have a table which lists the dates, having a TradingDayNumber... then use that to facilitate your join.
SELECT orig.*, next_day.price, two_days.price
FROM Prices orig
JOIN
TradingDays d0
ON d1.date = orig.date
JOIN
TradingDays d1
ON d1.TradingDayNum = d0.TradingDayNum + 1
JOIN
TradingDays d2
ON d2.TradingDayNum = d0.TradingDayNum + 2
JOIN
Prices next_day
ON next_day.symbol = orig.symbol AND next_day.date = d1.date
JOIN
Prices two_days
ON two_days.symbol = orig.symbol AND two_days.date = d2.date
But obviously you'll need to construct your TradingDays table...
Rob
My guess is:
SELECT top10perday.date, top10perday.symbol, MIN(pnd.price) AS PriceNextDay, MIN(ptd.price) AS PriceTwoDays
FROM top10perday
LEFT OUTER JOIN prices AS pnd ON (pnd.symbol = top10perday.symbol AND pnd.date > top10perday.date)
LEFT OUTER JOIN prices AS ptd ON (ptd.symbol = top10perday.symbol AND ptd.date > pnd.date)
GROUP BY top10perday.date, top10perday.symbol
HAVING ((pnd.date = Min(pnd.date) AND ptd.date = Min(ptd.date));
It´s just a shoot in the dark but my reasoning is: List all stocks you want (top10perday) and for each stock get the price, if exists, with mininum date after its date to populate the PriceNextDay and the price with minimun date after the PriceNextDay to populate the PriceTwoDays. The performance may stinks. But test it and see if it works. Later we can try to improve it.
**EDIT**ed to include Rob Farley´s comment.
I'm not a guru on this transformation but I can point you at an idea. Try using Pivot on the date column for each symbol in your query from a date to a date. This should give you a table with many columns with the name of the date you're using, and the price on each day. Indeed it should do this for every stock symbol you have over a given time.
Based on what you're trying to graph though, I think it would be interesting for you to look at the VWSP not just the spot price on your trades if you're trying to plot the stock performance.