oracle query need to compare and get result in the same query - oracle

I have a query which fetch record from one db and insert it into another db across servers using script.
the query is like :-
select id, date, iscomplete
from sourcedb.test where id = '1'
and date = '2011-03-15' and iscomplete = 1;
this query returns me some records, which i want only when there are certain number of records.
for ex:- there are 10 records for '2011-03-15' then I want to fetch those 10 records only when is complete is 1 for all the 10 records.
I dont want to hardcode it as records can increase in near future from 10 to 20.
Is there any way I can modify my original query and check if iscomplete = 1 for all the records for that day then fetch the records else return nothing.
I need to add one more condition to this query that is if there are 10 records and half of them are completed i.e. isComplete = 1 and half of them are isComplete <> 1 in this case I dont want any output from the query untill and unless all the record has isComplete = 1.
Regards,
Manasi

Just make the next check
select id, date, iscomplete
from sourcedb.test
where id = '1'
and date = '2011-03-15'
and not exists (select 1 from sourcedb.test where id = '1'
and date = '2011-03-15' and isComplete <> 1);

Related

Limit user to post certain number of comments per article

Somehow I'm running in circles for two days! I have MySQL Database and comments table in witch I have id, user_id, date, published_at, body, likes and dislikes. How to limit user for max 10 comments per day. Of course I have user table.
I know I have somehow to count number of comments for certain date and put it in security context but I don't know how. I've tried with some native queries in
Repository like:
#Query(value = "select count from comments WHERE published_at=?1 AND user_id=?2", nativeQuery = true)
public int brojPostovaPoDanuPoUseru(Date datum, Integer user_id);
I guess I should find logged user name from SecurityContext and after that find his id, but then again what if there are two users with a same name, and where to use SecurityContext to find this.
At least some guidelines please :)
You can implement this on database level. My idea would be to save the time in seconds in date ( using Java: System.currentTimeMillis()). Then when you query by the user id, you can sort the results by date in descending order and filter for the top 10. Then you would pick the smallest number in date and check if it was less then 24h ago, if so you could then return an exception.
This would be an example query:
select * from (SELECT * FROM `comments` where comments.user_id=?1 ORDER BY `comments`.`date` DESC limit 10) as c order by c.date ASC limit 1
Let's say you saved date in secods using System.currentTimeMillis() / 1000. Now with the query result you would first calculate the seconds in hours and then in a day. This results in 86400 seconds. Now you would calculate the current time in seconds and extract it with the 24h in seconds as calculated before. And then you would check if this calculated result is smaller than the value of date this would indicate that the last 10th comment was made within the 24 hours.
This is the sample code in your repository:
#Query("select * from (SELECT * FROM `comments` where comments.user_id=?1 ORDER BY `comments`.`date` DESC limit 10) as c order by c.date ASC limit 1", nativeQuery=true)
public Comments getLastTenthComment(int userId);
This is the sample code in your service:
public boolean isAllowedToComment(int userId){
Comment comment = repository.getLastTenthComment(userId);
int dayInSeconds = 86400;
long currentTime = System.currentTimeMillis() / 1000;
long yesterdayInSeconds = currentTime - dayInSeconds;
if(comment.getDate() >= yesterdayInSeconds){
return false;
}
return true;
}

find rows with same value using LINQ

The issue with the image above is that
I want to apply a bonus share to the shareholders based on the TransLog_Date
Because the shareholder in row 1 has already transferred a portion of his shares to the holder in row 3, his new share value is what shows in row 2 column 5 as 100000
I want the bonus share to be calculated based on the value in row 2, column 5 but not on row 1, column 5.
I have tried several codes in LINQ but getting it wrong as the value is multiplied on all the 3 records which is totally wrong.
var transQuery = (from tq in db.TransactionsLogDbSet
where (tq.TransactionType == TransactionType.PurchaseOfShares)
|| (tq.TransactionType == TransactionType.TransferOfShares)
|| (tq.TransactionType == TransactionType.BonusSharesDeclared)
select tq);
var query = from row in db.TransactionsLogDbSet
group row by row.Transholder_ID into g
select new { Count = g.Count() };
OK, i think I finally got what you want.
Is that right?: Group all rows of some TransactionTypes by the Transholder_ID, then from each group select the row with the maximum Translog_Date, giving you the most recent row per Transholder_ID. Once you have the result of that, you can iterate over it to calculate whatever you need.
from t in db.TransactionLogDbSet
where where tq.TransactionType == TransactionType.PurchaseOfShares || tq.TransactionType == TransactionType.TransferOfShares || tq.TransactionType == TransactionType.BonusSharesDeclared
group t by t.Transholder_ID into g
select (from t1 in g orderby t1.Translog_Date descending select t1).First();
EDIT: I'll continue to edit the following part of my answer as long as we finally arrive at the correct query.
From you last comment so far it follows that you just want to select all rows with a TransLog_Date <= a given DateTime qualifiedDate.
from t in db.TransactionLogDbSet
where t.TransactionLog_Date <= qualifiedDate
select t
Is that it?

INDEX ON Date Range and a Uniqe Number VFP

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)

How to Select MAX column value from fetched SQL rows

I have SQL to get 5 rows... how do I get the max value from this fetch. for example I want 1990.75.
here are the results of the fetch
1990.25
1990.50
1990.00
1900.00
1990.75
Or if there is a better way? I need to get the last 5 records which are already sorted by date DESC and time DESC in the table (the 5 may change to another number)
DECLARE #CurrentSetNumber int = 0;
DECLARE #NumRowsInSet int = 5;
SELECT [Stock_High]
FROM [dbo].[HistData]
Where BarSize = '5 mins'
Order by RecordID
OFFSET #NumRowsInSet * #CurrentSetNumber ROWS
FETCH NEXT #NumRowsInSet ROWS ONLY;
SET #CurrentSetNumber = #CurrentSetNumber + 1;
TIA
The 5 rows/values that you have after sorting, stores those 5 values into a table variable or temp table and then get max of values from temp table.

Performance of User Defined Functions in SQL Server 2000 and 2005

We have two tables, Customer and CustomerEvent both contains few million rows. On SQL Server 2000, we deployed an UDF called fn_CustomerEvent which returns TRUE or FALSE based on two parameters CustomerID and EventCode, e.g.
SELECT dbo.fn_CustomerEvent(1345678, 'Music')
The UDF code is:
CREATE FUNCTION [dbo].[fn_CustomerEvent](#CustomerID INT, #EviCode NVARCHAR(10))
RETURNS NVARCHAR(10)
AS
BEGIN
DECLARE #List NVARCHAR(10)
SELECT #List = CASE
WHEN COUNT(*) > 0 THEN 'TRUE'
ELSE 'FALSE'
END
FROM CustomerEvent
WHERE
CustomerID = #CustomerID
AND EviCode = #EviCode
RETURN #List
END
The performance on SQL Server 2000 was great. Return TOP 5000 rows within 3 seconds. For example,
SELECT TOP 5000
CustomerID, dbo.fn_CustomerEvent(1345678, 'Music')
FROM [Table1]
But now, we are moving to SQL Server 2005. Same code, same UDF, but performance drops dramatically from 3 seconds to 1 minutes 20 seconds.
Can anyone point me a right direction on where should I start to optimize the performance?
The scalar UDF is evaluated for each row (i.e. 5000 times). You could either call it once and store the result in a variable
DECLARE #Result nvarchar(10)
SELECT #Result = dbo.fn_CustomerEvent(1345678, 'Music')
SELECT TOP 5000
CustomerID, #Result
FROM [Table1]
or you can use an inline TVF (and I would also use EXISTS instead of COUNT)
CREATE FUNCTION CustomerEvent (#CustomerID INT,
#EviCode NVARCHAR(10))
RETURNS TABLE
AS
RETURN
(SELECT CASE
WHEN EXISTS(SELECT *
FROM CustomerEvent
WHERE CustomerID = #CustomerID
AND EviCode = #EviCode) THEN 'TRUE'
ELSE 'FALSE'
END)
See Scalar functions, inlining, and performance: An entertaining title for a boring post for more about this technique.
There is one big problem with UDF's: they don't work with indexes. If you want to get code re-use and maintain performance, I will normally build either a computed column (which can be indexed) or a view.
CREATE FUNCTION CustomerEvent (#CustomerID INT,
#EviCode NVARCHAR(10))
RETURNS TABLE
AS
RETURN
(SELECT COALESCE((SELECT 'TRUE' FROM CustomerEvent
WHERE
CustomerID = #CustomerID
AND EviCode = #EviCode)
, 'FALSE'))
Check for Indexes, Rebuild Them and Update your statistics.

Resources