INDEX ON Date Range and a Uniqe Number VFP - sorting

I need to change a select statement in VFP to do a simple task (select all records in a date range and by a Employee Number). I have tried everything I can think of. I know I can do it in SQL select but I just want to use the table I have and not a cursor.
I'm trying something like this
INDEX ON Date >= ThisForm.DateFrom+Date + Date=< ThisForm.DateTo+ALLTRIM(empid) TAG MyOrder
I know how INDEX ON works but my format is wrong.

Maybe you meant a filtered index. However you don't need to do such a thing. You could simply have an index combining employee number (I suppose it is an integer) and the date. Then you can use a simple for and while scoping clauses or range or alike (you really didn't explain what you would do) - and even an SQL might be the easier way depending on what you would do.
ie: (using date as a column name is a bad idea, but that is another matter)
INDEX ON padl(empId, 10, '1') + dtoc(Date,1) TAG MyOrder
Having such an index you could scan all the records for a given employee in a date range like this:
local lnEmployee, lcStart, lcEnd
lnEmployee = 1 && whatever the employee number is
lcStart = padl(m.lnEmployee, 10, '1')+dtoc(ThisForm.DateFrom,1)
lcEnd = padl(m.lnEmployee, 10, '1')+dtoc(ThisForm.DateTo,1)
scan for padl(empId, 10, '1') + dtoc(Date,1) >= m.lcStart and ;
padl(empId, 10, '1') + dtoc(Date,1) <= m.lcEnd
* whatever
endscan
This would do the same:
local lnEmployee, lcStart, lcEnd
lnEmployee = 1 && whatever the employee number is
lcStart = padl(m.lnEmployee, 10, '1')+dtoc(ThisForm.DateFrom,1)
lcEnd = padl(m.lnEmployee, 10, '1')+dtoc(ThisForm.DateTo,1)
set order to tag myOrder
set range to m.lcStart, m.lcEnd
scan
* whatever
endscan
PS: Actually with indexes on empid and date, a simple scan for ... would do too. ie:
scan for empId = m.lnEmpoyee and ;
Date >= ThisForm.DateFrom and ;
Date <= ThisForm.DateTo
*...
endscan

Welp don't really like filter but if any one has a better idea let me know!
Set Filter To Date >= ThisForm.DateFrom .And. Date =< ThisForm.DateTo .And. EmpID = AllTrim(ThisForm.Combo1.Value)

Related

How to generate a random char in oracle

I have a column in my table in which I can insert M or F, according to the user's gender (Male or Female).
I need to generate this column randomly.
This column type is VARCHAR2(1).
I think I should use something like :
TRUNC(dbms_random.value(X,X))
But I dont know how.
Since dbms_random.value returns a value >= 0 and < 1, I'd just use something like this assuming you want an equal probability of getting an M or an F. If you want to produce a skewed distribution, adjust the 0.5 value to whatever you'd like
case when dbms_random.value < 0.5
then 'M'
else 'F'
end

Elegant way to make a SUm

I need a query (in Oracle), that will be inside a stored procedure, where I can get a sum of the Amount value of Table REV.
The YEAR and one MONTH will be received as a parameter in the stored procedure, as YY and MM.
What I want is to sum the amount values since the 1st month of the year UP to the MM passed in the argument.
So
if MM in the argument is 02, I want to take the sum of amounts of months 01 + 02
if MM in the argument is 05, I want to take the sum of amounts of months 01+02+03+04+05
So MM is the last month to be summed.
How can I make this in the most efficient and elegant way?
CREATE OR REPLACE PROCEDURE "GET_YTD_AMOUNT" (YY in VARCHAR,
MM in VARCHAR)
select
ACT.LABEL ,
R.YEAR,
R.MONTH,
sum(R.AMOUNT)
from
ACTIVITY ACT,
REV R
where
R.YEAR=YEAR and
R.MONTH ??
R.ID_CODE = ACT.ID_CODE
I'd prefer using numeric variables rather than strings for such cases.
In your case ;
considering your year and month parameters are of string type, you need a to_number() conversion with less than or equal to operator
to_number(R.MONTH) <= to_number(i_month)
add an out parameter o_amount to return the result you get
of course, you need to convert your SQL format containing explicit
joins
better to define parameters ( or local variables ) by their type
within the tables in which they're contained. Btw, I didn't define o_amount by rev.amount%type against probability of sum() aggregation might exceed the precision of numeric value provided it's defined as so within the table.
So,use :
CREATE OR REPLACE PROCEDURE GET_YTD_AMOUNT(
i_year in rev.year%type,
i_month in rev.month%type,
o_amount out number
) IS
BEGIN
select sum(r.amount)
into o_amount
from activity a
join rev r
on r.id_code = a.id_code
where r.year = i_year
and to_number(r.month) <= to_number(i_month);
END;
/
You can use less than equal to:
select
ACT.LABEL ,
R.YEAR,
Max(R.MONTH) || '-' || Max(R.MONTH) as months_from_to
sum(R.AMOUNT)
from
ACTIVITY ACT,
REV R
where
R.YEAR= YY and -- it should be YY
R.MONTH <= MM -- less than equal to with MM
R.ID_CODE = ACT.ID_CODE
Group by ACT.LABEL ,
R.YEAR
Note: You must re-design your DB to store dates in date data type.
Cheers!!

Using the data from a for loop as a table in the From in a Select

I am converting some code in Access over to Oracle, and one of the queries in Access uses a table that I am unable to use in Oracle. I am unable to create new tables, so I am trying to figure out a way to use the logic behind the table in the FOR section of my select.
The logic of the table is similar to:
FOR i = 1 To 100
number = number + 1
.AddNew
!tbl_number = number
NEXT i
I'm trying to convert this to oracle, and so far I have:
FOR i in 1 .. 100 LOOP
number := number + 1;
--This is where I am stuck; How do I simulate the table part
END LOOP;
I was thinking a cursor or a record would be the answer, but I can't seem to figure out how to implement that. In the end I basically want to have:
SELECT
table.number
FROM
(
--My for loop logic
) table
EDIT
The calculation is a bit more complicated; that was just an example. They aren't actually sequential, and there isn't really a pattern to rows.
EDIT
Here is a more complicated version of the for loop which is closer to what I'm actually doing:
FOR i in 1 .. 100 LOOP
number1 := number1 + 7;
number2 := (number2 + 8) / number1;
--This is where I am stuck; How do I simulate the table part
END LOOP;
You could use a recursive query (assuming you are on Oralce 11gR2 or later):
with example(idx, number1, number2) as (
-- Anchor Section
select 1
, 1 -- initial value
, 2 -- initial value
from dual
union all
-- Recursive Section
select prev.idx + 1
, prev.number1 + 7
, (prev.number2 + 8) / prev.number1
from example prev
where prev.idx < 100 -- The Guard
)
select * from example;
In the Anchor section set all the values for your first record. Then in the Recursive section setup the logic to determine the next records values as a function of the prior records values.
The Anchor section could select the initial values from some other table rather than being hard coded as in my example.
The recursive section needs to select from the named subquery (in this case example) but may also join to other tables as needed.
You need to generate a set with sequential integer numbers. Maybe you can use this (for Oracle 10g and above):
SELECT
ROWNUM NUM
FROM
DUAL D1,
DUAL D2
CONNECT BY
(D1.DUMMY = D2.DUMMY AND ROWNUM <= 100)

Automate bulk of update queries in pl\sql

For frequent period of time, i'm doing same process of updating few tables with consecutive values. Hope to make this simple an example below,
UPDATE Table_1 SET vchar_val = REPLACE (vchar_val, '.360/', '.370/'),
WHERE vchar_val LIKE 'http://services%.360/%'
AND c_version IN ('ALL', 'N/A', '37.0');
For 37th version, i'm replacing the places where '36' with '37'. The same i'll do for '38' and it continues...This is making me bore and time consuming process as i've 50 plus records like this for different tables for which i'm manually editing all update queries.
So i planned to write a scheduler which i can trigger for each version by giving input as previous version and current version, in which i'll put all this update queries.
Here comes the place where i struck, if i go by giving version values as input, i'm supposed to introduce local parameter to store. HOW CAN I ASSIGN THAT LOCAL VARIABLE TO MY UPDATE SCRIPT.??????
I go with concatenate the texts like
REPLACE (vchar_val, '.'+ #PrevVersion +'/', '.'+ #CurrentVersion +'/')
PrevVer** & CurrentVer** is my local variable with values .360 & .370 resp.
I think i miss quiet piece of code in this snippet as i'm getting error when running this.
Please help me guys to rearrange this code to automate the query or ur comments to do this job in any alternative way...
Thanks
-VIno
begin
for i in 36 .. 50 loop
UPDATE Table_1
SET vchar_val = REPLACE (vchar_val, '.'|| i ||'0/', '.'|| i+1 ||'0/')
WHERE vchar_val LIKE 'http://services%.'|| i ||'0/%'
AND c_version IN ('ALL', 'N/A', i+1 ||'.0');
end loop;
end;
Of course you could do that in one single update with some fancy reg_exp, but I leave that exercice to another fellow stackoverflower :)
Local variable:
declare
my_local_valiable number;
begin
update my_table ... ;
commit;
end;
Autoincrement: sequence
update table_1 set my_field = '.' || my_sequence.nextval where ...;
UPD
Number always in the same position (for example, 2 digits, 10th and 11th symbols in the string):
update table_1 set my_field = substr(my_field, 1, 9) || to_char(to_number(substr(my_field, 10, 2)) + 1) || substr(my_field, 12);
This converts string 'abracadab29ra' to 'abracadab30ra'.
The same with replace:
update table_1 set my_field = replace(my_field, substr(my_field, 10, 2), to_char(to_number(substr(my_field, 10, 2)) + 1));
Number always follows after a string 'value = ' and has two digits:
update table_1 set my_field = replace(my_field, substr(my_field, instr(my_field, 'value = ', 1) + 8, 2), to_char(to_number(substr(my_field, instr(my_field, 'value = ', 1) + 8, 2)) + 1))
This converts string 'my value = 33' to 'my value = 34'.

DATEDIFF (in months) in linq

select col1,col2,col3 from table1
where(DATEDIFF(mm, tblAccount.[State Change Date], GETDATE()) <= 4
I want to convert this sql query to LINQ. but I dont know any DateDiff alternative in LINQ. can you please suggest me?
You're looking for SqlMethods.DateDiffMonth.
EDIT: In EF4, use SqlFunctions.DateDiff.
Putting aside your original question for a moment, in your query you use:
where(DATEDIFF(mm, tblAccount.[State Change Date], GETDATE()) <= 4
This query would always cause a full table scan, since you're comparing the result of a function call against a constant. It would be much better if you calculate your date first, then compare your column value against the calculated value, which would allow SQL to use an index to find the results instead of having to evaluate every record in your table.
It looks like you're trying to retrieve anything within the past 4 months, so in your application code, try calculating the date that you can compare against first, and pass that value into your Linq2Entities expression:
DateTime earliestDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddMonths(-4);
var results = from t in context.table1
where t.col3 >= earliestDate
select t;
In EF6, the class to use is DbFunctions. See, for example, DbFunctions.DiffMonths.
I solved this problem in another manner: I calculated the date from code:
theDate = Date.Now.AddMonths(-4)
And in EF change the condition:
tblAccount.[State Change Date] < theDate

Resources