I am using an MS Access database and am trying to make a query that provides an overview of securities for which the price changed by more than XX% during the last XY consecutive months. I have tried all kind of subqueries but cannot get my head around this.
Please find below a simplified example. The PriceTable contains three attributes: a period, a security id and the price of the security in that period. I am looking for a query that provides me per the last period (in this case 201210) all securities having a price change of more than plus or minus XX% (in this case 3%) in the last XY (in this case 3) months. The three columns on the right hand provide some calculations to further clarify this:
Delta is the price change from one period to the other ((PT-PT-1)/PT-1)
Delta>Threshold: checks whether the change is larger than (plus or minus) 3% (parameter XX)
Counter: checks whether the price change is larger than 3% for 3 (parameter XY) consecutive months
In the example below the query should only show productID number 1.
PriceTable Supporting calculations
+--------+------+-------+--------+-----------------+---------+
+ Period |SecID | Price | Delta% | Delta>Threshold | Counter |
+--------+------+-------+--------+-----------------+---------+
| 201206 | 1 | 105 | 0% | N | 0 |
| 201207 | 1 | 100 | -4.76% | Y | 1 |
| 201208 | 1 | 95 | -5% | Y | 2 |
| 201209 | 1 | 90 | -5.26% | Y | 3 |
| 201210 | 1 | 85 | -5.56% | Y | 4 |
| 201207 | 2 | 95 | 0% | N | 0 |
| 201208 | 2 | 100 | 5.26% | Y | 1 |
| 201209 | 2 | 103 | 3% | N | 0 |
| 201210 | 2 | 99 | -3.88% | Y | 1 |
+--------+------+-------+--------+-----------------+---------+
I hope someone can help me out!
Thanks in advance,
Paul
I don't have Access to hand, but here's a query for SQL Server:
The inner 'h' table is pretty much your helper table. the outer bit joins on 3 periods, and displays if the count with threshold 'Y' is 3
The way I did it you also need functions for working out the next period, and the number of periods between two end points. These should be fairly easy to write in VBA. You could also create a period table with a sequence number to work around this:
-- Function that works out the next period
-- i.e. if you supply 201112, it will return 201201
Create Function dbo.NextPeriod(#Period As Int) Returns Int As
Begin
Declare
#Month int,
#Ret int = Null
If #Period Is Not Null
Begin
Set #Month = #Period - 100 * (#Period / 100)
If #Month < 12
Set #Ret = #Period + 1
Else
Set #Ret = #Period - #Month + 101
End
Return #Ret
End;
-- Function that works out how many periods between the two endpoints
-- dbo.PeriodCount(201112, 201201) = 1
Create Function dbo.PeriodCount(#StartPeriod As Int, #EndPeriod As Int) Returns Int As
Begin
Declare
#StartMonth int,
#EndMonth int,
#StartYear int,
#EndYear int,
#Ret int = Null
If #StartPeriod Is Not Null And #EndPeriod Is Not Null
Begin
Set #StartMonth = #StartPeriod - 100 * (#StartPeriod /100)
Set #StartYear = (#StartPeriod - #StartMonth) / 100
Set #EndMonth = #EndPeriod - 100 * (#EndPeriod / 100)
Set #EndYear = (#EndPeriod - #EndMonth) / 100
Set #Ret = (12 * #EndYear + #EndMonth) - (12 * #StartYear + #StartMonth)
End
Return #Ret
End;
-- Show periods that are the start of a run
-- of #Periods periods with threshold
-- of at least #Threshold
Declare #Threshold Decimal(10, 2) = 3
Declare #Periods int = 3
Select
p0.SecurityID,
p0.Period
From
PriceTable p0
Inner Join (
Select
p1.*,
100 * (p1.Price - p2.Price) / p2.Price As Delta,
Case When Abs(100 * (p1.Price - p2.Price) / p2.Price) > #Threshold Then 'Y' Else 'N' End As OverThreshold
From
PriceTable p1
Left Outer Join
PriceTable p2
On p1.SecurityID = p2.SecurityID And
p1.Period = dbo.NextPeriod(p2.Period)
) h
On p0.SecurityID = h.SecurityID And
dbo.PeriodCount(p0.Period, h.Period) Between 0 And (#Periods - 1) And
h.OverThreshold = 'Y'
Group By
p0.SecurityID,
p0.Period
Having
Count(*) = #Periods
Order By
p0.SecurityID,
p0.Period;
This shows you how the method works, you can simplify it like so:
Declare #Threshold Decimal(10, 2) = 3
Declare #Periods int = 3
Select
p0.SecurityID,
p0.Period
From
PriceTable p0
Inner Join
PriceTable p1
On p0.SecurityID = p1.SecurityID And
dbo.PeriodCount(p0.Period, p1.Period) Between 0 And (#Periods - 1)
Inner Join
PriceTable p2
On p1.SecurityID = p2.SecurityID And
p1.Period = dbo.NextPeriod(p2.Period)
Where
Abs(100 * (p1.Price - p2.Price) / p2.Price) > #Threshold
Group By
p0.SecurityID,
p0.Period
Having
Count(*) = #Periods
Order By
p0.SecurityID,
p0.Period;
http://sqlfiddle.com/#!3/8eff9/2
#Laurence: please find below the code
Public Function NextPer(Nperiod As Long) As Long
Dim Month As Long
If Not IsNull(Nperiod) Then
Month = 100 * ((Nperiod / 100) - Round(Nperiod / 100, 0))
If Month < 12 Then
NextPer = Nperiod + 1
Else
NextPer = Nperiod - Month + 101
End If
End If
End Function
Public Function PCount(SPeriod As Long, EPeriod As Long) As Long
Dim SMonth As Long
Dim EMonth As Long
Dim SYear As Long
Dim EYear As Long
If Not IsNull(SPeriod) And Not IsNull(EPeriod) Then
SMonth = 100 * ((SPeriod / 100) - Round(SPeriod / 100, 0))
SYear = (SPeriod - SMonth) / 100
EMonth = 100 * ((EPeriod / 100) - Round(EPeriod / 100, 0))
EYear = (EPeriod - EMonth) / 100
PCount = (12 * EYear + EMonth) - (12 * SYear + SMonth)
End If
End Function
And the QUERY (the parameters are for the moment hardcoded)
SELECT p0.SecurityID, p0.Period
FROM (PriceTable AS p0
INNER JOIN PriceTable AS p1 ON (p0.SecurityID = p1.SecurityID)
AND (PCount(p0.Period,p1.Period)>=0) AND (PCount(p0.Period,p1.Period)<=2))
INNER JOIN PriceTable AS p2 ON (p1.SecurityID = p2.SecurityID)
AND (p1.Period = NextPer(p2.Period))
WHERE Abs(100*(p1.Price-p2.Price)/p2.Price)>0.03
GROUP BY p0.SecurityID, p0.Period
HAVING Count(*) = 3
ORDER BY p0.SecurityID asc , p0.Period asc;
+1 for your intention of trying to get this in query itself without UDFs. Out of extreme interest I have put some effort to find a solution. I admit following code is not the most efficient code. (with all those IIFs, the performance is not that great)
Getting first 5 columns as per your above table are pretty straightforwad. I have saved that in qryDelta. I find the tricky part of the question is to have Counter in the same results table. Second query qryCounter will give you the final table as you expected.
qryDelta
SELECT a.period, a.secid, a.price,
iif(isnull(ROUND((a.price-b.price)/b.price*100,2)),0,
ROUND((a.price-b.price)/b.price*100,2)) AS Delta,
iif(abs((a.price-b.price)/b.price)*100>3,"Y","N") AS Threshold,
SUM(iif(abs((a.price-b.price)/b.price)*100>3,1,0)) AS [Counter]
FROM tbldelta AS a LEFT JOIN tbldelta AS b
ON (a.secid = b.secid) AND (a.period = b.period + 1)
GROUP BY a.period, a.secid, a.price,
iif(isnull(ROUND((a.price-b.price)/b.price*100,2)),0,
ROUND((a.price-b.price)/b.price*100,2)),
iif(abs((a.price-b.price)/b.price)*100>3,"Y","N")
ORDER BY a.secid, a.period;
Results:
qryCounter
SELECT q.period, q.secid, q.price, q.delta, q.threshold,
SUM(iif(q.counter=0,0,1)) AS Counter
FROM qryDelta q
LEFT JOIN tblDelta t
ON q.secid = t.secid
AND (t.period < q.period)
GROUP BY q.secid, q.period, q.price, q.delta, q.threshold
Results:
However I too faced the issue with SecId = 2, Period = 201208 with a total = 2. So I changed my query conditions. Now the results seem to show the cumulative periodic count properly except for SectID = 2, Period = 201210 total = 3. Perhpas you guys could throw some light to this. Out of most of the experiments done, it seems more or less a bug on JOIN and between dates that we are trying to put as coditions here.
PS:
If you have decided to build user defined functions (UDF), then you may consider two things. Are you using Excel as front end or Access as front end. Then you have to provide necessary arrangements to call your Access UDF & query from Excel. If you are only using Access as both front and back end, then ofcourse using a UDF would be much easier to handle.
I solved it using just SQL. Here's how I did.
First of all, we need a query that, for each rows, shows the distance in rows from the last period:
Period SecID Price Row
===============================
201206 1 105 4
201207 1 100 3
201208 1 95 2
201209 1 90 1
201210 1 85 0
201207 2 95 3
201208 2 100 2
201209 2 103 1
201210 2 99 0
we will call it PriceTable_Ordered:
SELECT
PriceTable.Period,
PriceTable.SecID,
PriceTable.Price,
(select count(*) from PriceTable PriceTable_1
where PriceTable_1.SecID = PriceTable.SecID
AND PriceTable_1.Period > PriceTable.Period) AS Row
FROM PriceTable;
Now to calculate the Delta, and showing if the Delta is more than the threesold, we can use this query that we will call PriceTable_Total1:
SELECT
PriceTable_Ordered.*,
PriceTable_Ordered_1.Price,
(PriceTable_Ordered.Price-PriceTable_Ordered_1.Price)/(PriceTable_Ordered_1.Price) AS Delta,
iif((ABS(Delta*100)>3),"Y","N") AS DeltaThreesold
FROM
PriceTable_Ordered LEFT JOIN PriceTable_Ordered AS PriceTable_Ordered_1
ON (PriceTable_Ordered.SecID = PriceTable_Ordered_1.SecID)
AND (PriceTable_Ordered.[Row]=PriceTable_Ordered_1.[Row]-1);
And this returns:
Period SecID Price1 Row Price2 Delta DeltaThreesold
=========================================================
201206 1 105 4 N
201207 1 100 3 105 -4,76 Y
201208 1 95 2 100 -0,05 Y
201209 1 90 1 95 -5,26 Y
201210 1 85 0 90 -5,55 Y
201207 2 95 3 N
201208 2 100 2 95 5,26 Y
201209 2 103 1 100 0,03 N
201210 2 99 0 103 -3,88 Y
Now we can create PriceTable_Total2 based on PriceTable_Total1:
SELECT
PriceTable_Total1.Period,
PriceTable_Total1.SecID,
PriceTable_Total1.PriceTable_Ordered.Price,
PriceTable_Total1.Delta,
PriceTable_Total1.DeltaThreesold,
PriceTable_Total1.Row,
(select min(row) from PriceTable_Total1 PriceTable_Total1_1
where PriceTable_Total1.SecID = PriceTable_Total1_1.SecId
and PriceTable_Total1.Row < PriceTable_Total1_1.Row
and PriceTable_Total1_1.DeltaThreesold="N") AS MinN,
IIf([DeltaThreesold]="Y",[MinN]-[row],0) AS CountRows
FROM PriceTable_Total1;
we select all the columns of PriceTable_Total1, then for each row we count the minimum row number > than current row where threesold is "N". If current row is over threesold, the count we need is just this difference, otherwise it's 0. Here's the result:
Period SecID Price Delta DelTh Row MinN CountRows
========================================================
201206 1 105 N 4 0
201207 1 100 -4,76 Y 3 4 1
201208 1 95 -0,05 Y 2 4 2
201209 1 90 -5,26 Y 1 4 3
201210 1 85 -5,55 Y 0 4 4
201207 2 95 N 3 0
201208 2 100 5,26 Y 2 3 1
201209 2 103 0,03 N 1 3 0
201210 2 99 -3,88 Y 0 1 1
You can then hide the columns that you don't need. This query should work even if we cross the year and even if some periods are missing.
SELECT PriceTable_Total2.Period, PriceTable_Total2.SecID
FROM PriceTable_Total2
WHERE (PriceTable_Total2.Period=
(select max(period)
from PriceTable
where PriceTable.SecID=PriceTable_Total2.SecID)
AND (PriceTable_Total2.[CountRows])>=3);
this will return:
Period SecID
201210 1
and that means that only SecID 1 is over threesold in the last period for more than 3 months.
I hope this answer is correct, it was nice to try to solve it!!
Related
I want to fill null value with a new price value. The new price value will calculated from the other product available price (same product) times the factor.
given table,
Prod | unit | factor | price
abc X 1 24000
abc Y 12 NULL
xyz X 1 NULL
xyz y 5 60000
xyz Z 20 NULL
that formula that comes to mind
null price = avail same prod price * it's factor/null price factor
with the existing table above, examples price formula will be
'abc Y price' = 20000 * 1 / 12 = 2000 (avail price is abc X)
'xyz X price' = 60000 * 5 / 1 = 300000 (avail price is xyz Y)
'xyz Z price' = 60000 * 5 / 20 = 15000 (avail price is xyz Y)
is there any way i can do this?
I think this does what you want:
select t.*,
coalesce(price,
max(price * factor) over (partition by prod) / factor
) as calculated_price
from t;
This replaces NULL prices with the maximum price * factor for the product -- then divided by the factor on the given row.
Below is for BigQuery Standard SQL
if a product has 2 or more price list, just fill the null with the lowest factor
#standardSQL
SELECT t.* REPLACE(IFNULL(t.price, t.factor * p.price / p.factor) AS price)
FROM `project.dataset.table` t
LEFT JOIN (
SELECT prod, ARRAY_AGG(STRUCT(price, factor) ORDER BY factor LIMIT 1)[SAFE_OFFSET(0)].*
FROM `project.dataset.table`
WHERE NOT price IS NULL
GROUP BY prod
) p
USING(prod)
If to apply to sample from your question - result is
Row prod unit factor price
1 abc X 1 24000.0
2 abc Y 12 288000.0
3 xyz X 1 12000.0
4 xyz Y 5 60000.0
5 xyz Z 20 240000.0
Note: it looks like in your formula you need to reverse factors - for example 60000 * 20 / 5 - not sure, but this looks more logical for me. If I am wrong you can adjust t.factor * p.price / p.factor and use p.factor * p.price / t.factor instead
In this case result will be (which matches what you expected but as I said already I suspect is wrong -but it is up to you obviously)
Row prod unit factor price
1 abc X 1 24000.0
2 abc Y 12 2000.0
3 xyz X 1 300000.0
4 xyz Y 5 60000.0
5 xyz Z 20 15000.0
I've put together a small database to keep track of some accumulator bets that a few of my colleagues and I place during the football season. Now I need to write a function to calculate the winnings for each selection. The key table is selection with the key fields for the function being odds and result_id where a result_id of 1 is a win. The stake is stored in the bet table. Below is the selection table which has two winners for bet_id 1, so the resulting equation would be ((#stake * 1.40) * 1.40). Is there a way using a cursor or a set based method to generate this value?
bet_id punter_id team_id odds result_id ground_id
1 1 24 1.40 1 1
1 1 48 1.60 2 1
1 1 89 1.60 2 1
1 2 8 1.40 1 1
1 2 11 1.60 2 1
1 2 107 1.60 2 1
Assuming you join on bet_id:
CREATE TABLE bet (bet_id int NOT NULL PRIMARY KEY,
stake float NOT NULL); -- or some floating point number type
To multiply a group we use the following relationship:
log( a * b * c ) = log(a) + log(b) + log(c)
And therefore for multiplication
a * b * c = exp( log( a * b * c ) ) = exp( sum( log(.) ) )
To calculate the factors
bet_id | odds_factor
1 | 1.40 * 1.40 = 1.96
we use the Common Table Expression CTE in this query
WITH factor( bet_id, odds_factor ) AS
( SELECT bet_id, exp( sum( log( odds ) ) )
FROM selection
WHERE result_id = 1 -- only winning odds in the grouping
GROUP BY bet_id )
SELECT b.bet_id,
b.stake,
f.odds_factor,
b.stake * f.odds_factor AS "total_odds"
FROM bet b
INNER JOIN factor f
ON b.bet_id = f.bet_id
-- ORDER BY b.bet_id -- optional ordering for readability
which should yield (untested)
bet_id | stake | odds_factor | total_odds
1 | 10.0 | 1.96 | 19.6
Think this is as simple as:
SELECT B.BET_ID,
S.PUNTER_ID,
((B.stake * S.odds) * S.odds)
FROM BET AS B
INNER JOIN SELECTION AS S ON B.Bet_id = S.Bet_id
WHERE S.result_id = 1
I have a table Master_History with structure as
Id_History Created_Date Subscription_Type rn
21 1/22/2016 16:31:29 1 1
22 1/22/2016 16:33:11 2 2
23 1/22/2016 16:33:37 1 3
24 1/22/2016 16:33:46 2 4
25 1/22/2016 16:33:53 1 5
26 1/22/2016 16:33:57 3 6
27 1/22/2016 16:34:01 2 7
28 1/22/2016 16:34:04 1 8
29 1/22/2016 16:34:08 3 9
I want to calculate date difference with adjacent rows which i have succeeded in calculating but results are getting distributed over multiple rows
Standard Plus Premium
122 NULL NULL
NULL 35 NULL
NULL NULL 3
I need
Results in one row like
Standard Plus Premium
122 35 3
For the last row (in this Subscription_Type is 3, the date difference should also get calculated on getdate() i.e. whenever i executed my query, seconds in Premium column should get reflected each time
Query :
WITH CTE
AS (
SELECT *
,ROW_NUMBER() OVER (
ORDER BY Created_Date
) AS rn
FROM Master_History
WHERE Client_ID = 11072
)
SELECT CASE
WHEN mc.Subscription_Type = 1
THEN Sum(DATEDIFF(second, mc.Created_Date, mp.Created_Date))
END AS [Standard]
,CASE
WHEN mc.Subscription_Type = 2
THEN Sum(DATEDIFF(second, mc.Created_Date, mp.Created_Date))
END AS Plus
,CASE
WHEN mc.Subscription_Type = 3
THEN Sum(DATEDIFF(second, mc.Created_Date, mp.Created_Date))
END AS Premium
FROM CTE mc
JOIN CTE mp ON mc.rn = mp.rn - 1
GROUP BY mc.Subscription_Type
try this
select
count(Standard.*) Standard_,
count(Plus.*) Plus_,
count(Premium.*) Premium_
from
Master_History master_
left outer join Master_History Standard on Standard.Subscription_Type = 1
and master_.Subscription_Type = Standard.Subscription_Type
left outer join Master_History Plus on Plus.Subscription_Type = 2
and master_.Subscription_Type = Plus.Subscription_Type
left outer join Master_History Premium on Premium.Subscription_Type = 3
and master_.Subscription_Type = Plus.Subscription_Type
where
convert(date,master_.Created_Date) < convert(date,getdate()) and
convert(date,master_.Created_Date) < convert(date,Standard.Created_Date) and
convert(date,master_.Created_Date) < convert(date,Plus.Created_Date) and
convert(date,master_.Created_Date) < convert(date,Premium.Created_Date)
I just need advice on how I could speed up my code. I'm supposed to count on yearly base, how the grades of some students are improving and calculate in percentage. Also keep in mind that I have around 100k-150k records per year.
Basically end results look like this, so at end of 20150131, 2% of students had grade A finished with grade B and so on.
Grade Date B C
A 20150131 2% 3%
B 20150131 88% 85%
C 20150131 10% 12%
A 20140131 2% 3%
B 20140131 88% 85%
C 20140131 10% 12%
A 20130131 2% 3%
B 20130131 88% 85%
C 20130131 10% 12%
Input looks like this .. just info about student and his grade on certain date
Student Date Grade
1 20150131 A
2 20150131 C
3 20150131 A
1 20140131 B
2 20140131 B
3 20140131 A
My code looks like this:
WHILE #StartDateInt > #PeriodSpan
BEGIN
while #y <= #CategoriesCount
BEGIN
set #CurrentGr = (Select Grade from #Categories where RowID = #y)
set #CurrentGrCount = (Select COUNT(Students) from #TempTable where Period = #PeriodSpan and Grade = #CurrentGr)
set #DefaultCurrentGr = (Select Grade from #Categories where RowID = #y)
insert into Grade_MTRX (Student, Period, Grades_B, SessionID)
select temp1.Grade, #PeriodNextSpan as Period, COUNT(Grades_B)/#CurrentGrCount as 'Grades_B', #SessionID
from #TempTable temp1
join #TempTable temp2 on temp1.Student = temp2.Student and temp1.Period + 10000 = temp2.Period
where temp1.Grade = #CurrentGr and temp2.Grade = 'C' and temp1.Period = #PeriodSpan
group by temp1.Grade, temp1.Period
update Grade_MTRX set Grades_C = (
select COUNT(Grades_C)/#CurrentGrCount
from #TempTable
where Grade = 'C' and Period = #PeriodNextSpan)
where Category = #CurrentGr and Period = #PeriodNextSpan
end
end
I understand SQL Server doesn't like while loops, as I understand it kills it's performance... But I'm using while inside of while loop... going over years, for each grade and just counting them and... first I insert 1 row of current grade, and then I keep updating that row until its fully populated.
I do understand this is really bad, but at the end that's why I am here to learn better way to accomplish this.
Thank you in advance!
150,000 records per year is really nothing. Let's say you had this Grade table:
CREATE TABLE Grade(
student_id INT,
date INT,
grade CHAR);
With this info:
student_id date grade
1 2013 A
1 2014 A
1 2015 B
2 2013 B
2 2014 A
2 2015 C
3 2013 C
3 2014 A
3 2015 B
Then if you just run a query like:
SELECT this_year.date, last_year.grade AS last_year, this_year.grade AS this_year, COUNT(*) AS total,
(100.0 * COUNT(*)) / (SELECT COUNT(*) FROM Grade WHERE date = this_year.date) AS percent
FROM Grade AS this_year
INNER JOIN Grade AS last_year ON this_year.date = last_year.date + 1
AND this_year.student_id = last_year.student_id
GROUP BY this_year.date, this_year.grade, last_year.grade
ORDER BY 1, 2, 3;
you end up with these results:
date | last_year | this_year | total | percent
------+-----------+-----------+-------+---------------------
2014 | A | A | 1 | 33.3333333333333333
2014 | B | A | 1 | 33.3333333333333333
2014 | C | A | 1 | 33.3333333333333333
2015 | A | B | 2 | 66.6666666666666667
2015 | A | C | 1 | 33.3333333333333333
(5 rows)
Having a few million rows of data with this kind of query shouldn't be any real trouble. Even tens of millions of rows. But if you need things to be faster still then check out windowing functions that you can do with Postgres, Oracle, and MSSQL server.
I want to find the rows which are similar to each other, and update a field if a row has any similar row. My table looks like this:
OrderID | Price | Minimum Number | Maximum Number | Volume | Similar
1 45 2 10 250 0
2 46 2 10 250 0
3 60 2 10 250 0
"Similar" in this context means that the rows that have same Maximum Number, Minimum Number, and Volume. Prices can be different, but the difference can be at most 2.
In this example, orders with OrderID of 1 and 2 are similar, but 3 has no similar row (since even if it has same Minimum Number, Maximum Number, and Volume, but its price is not within 2 units from orders 1 and 2).
Then, I want to update the filed "Similar" for orders 1 and 2 from the default value (0) to 1. So, the output for the example above would be:
OrderID | Price | Minimum Number | Maximum Number | Volume | Similar
1 45 2 10 250 1
2 46 2 10 250 1
3 60 2 10 250 0
Here is one method that is ANSI standard SQL that will work in most databases, including Oracle. It implements the logic that you set out using a correlated subquery:
update table t
set similar = 1
where exists (select 1
from table t2
where t2.minimum = t.minimum and
t2.maximum = t.maximum and
t2.volume = t.volume and
abs(t2.price - t.price) <= 2 and
t2.OrderId <> t.OrderId
);
EDIT:
It occurs to me that the "similar" field might be the minimum OrderId of the similar fields. You can extend the above idea to:
update table t
set similar = (select min(orderId)
from table t2
where t2.minimum = t.minimum and
t2.maximum = t.maximum and
t2.volume = t.volume and
abs(t2.price - t.price) <= 2 and
t2.OrderId <> t.OrderId
)
where exists (select 1
from table t2
where t2.minimum = t.minimum and
t2.maximum = t.maximum and
t2.volume = t.volume and
abs(t2.price - t.price) <= 2 and
t2.OrderId <> t.OrderId
);
Although if this were the case, the default value should be NULL and not 0.