I am trying to count all rows that meet a criteria, and then also have it list sequence numbers for each row so we can quickly identify those meeting the criteria. Ex: We know 5 meet criteria of Complete Response and we want to know there are 5 but also what those sequence numbers are. How would i write that in my query?
select
count(sf.protocol_subject_id) as responseCount, sf.BEST_RESPONSE
from oncore.sv_sub_followup sf
where sf.protocol_no = $P{pPclNo} and sf.best_response is not null
group by sf.best_response
order by decode(best_response, 'Complete Response', 1, 'Partial Response', 2, 'Stable', 3, 'Progressive', 4, 'Not Evaluable', 5)
I should also mentioned that this is one of 9 subreports compiling a larger report. Not sure if that makes a difference when trying to do this. I'm very new to pl/sql. Thanks in advance for any help.
If I got this right, you need to count the rows for each BEST_RESPONSE for a given PROTOCOL_NO, and also list the IDs (protocol_subject_id) of those rows.
You could use the analityc function LISTAGG, that concatenates field values over a group. Something like this:
SELECT
best_response,
COUNT(protocol_subject_id) AS responsecount,
LISTAGG(protocol_subject_id, ', ') WITHIN GROUP (
ORDER BY
1
) matching_rows_ids
FROM
sv_sub_followup
WHERE
protocol_no = :protocol_no
AND best_response IS NOT NULL
GROUP BY
best_response
ORDER BY
decode(best_response, 'Complete Response', 1, 'Partial Response', 2,
'Stable', 3, 'Progressive', 4, 'Not Evaluable',
5);
You can use a subquery to obtain your results like the below
SELECT responsecount,
sf1.best_response,
sf1.protocol_subject_id
(
select count(sf.protocol_subject_id) AS responsecount,
sf.best_response
FROM oncore.sv_sub_followup sf
WHERE sf.protocol_no = $p{ppclno}
AND sf.best_response IS NOT NULL
GROUP BY sf.best_response)rec,
oncore.sv_sub_followup sf1
WHERE sf1.protocol_no=$p{ppclno}
AND sf1.best_response=rec.best_response
ORDER BY instr('Complete Response,Partial Response,Stable,Progressive,Not Evaluable',sf1.best_response);
Related
I need to get a query to get the below data:
to display like below:
basically adding a new column Vehicle_size for each value that is listed in the corresponding column. for example.
kay_SM = Vehicle_size(Small)
kay_LG= Vehicle_size(Large)
Lola_SM= Vehicle_size(Small)
lola_LG= Vehicle_size(Large)
at the same time create a new column:competitor, identifying if it is either for "lola" or "kay"
You can use unpivot in this case.
SELECT U.RENTAL_DATE,U.OUTBOUND,U.INBOUND,
REGEXP_SUBSTR(VEHICLE_COMPETITIOR, '[^_ ]+', 1, 2) AS VEHICLE_SIZE,
REGEXP_SUBSTR(VEHICLE_COMPETITIOR, '[^_ ]+', 1, 1) AS COMPETITIOR,
RATE
FROM T
UNPIVOT (
RATE FOR VEHICLE_COMPETITIOR IN (KAY_SM AS 'Kay_Small',
KAY_LG AS 'Kay_Large',LOLA_SM AS 'Lola_Small' ,LOLA_LG AS 'Lola_Large')
) U
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?
I am developing a report which should display the data horizontally.
What must be shown is the following:
email#1.com 12/09/2013 11/09/2013 10/09/2013 09/09/2013...
email#2.com 22/03/2013 21/03/2013 12/02/2013 02/01/2013...
Well, I have these data organized in two tables:
Member and Report.
The Member table has the email address and the Report table has dates, and each email can have many different dates.
I can easily retrieve that information vertically:
SELECT M.EMAIL, R.LAST_OPEN_DATE
FROM MEMBER M, REPORT R
WHERE M.MEMBER_ID = R.MEMBER_ID
AND R.STATUS = 1
AND TRUNC(R.LAST_OPEN_DATE) >= TRUNC(SYSDATE) - 120;
However to show the results horizontally is complicated, anyone have a tip or know how I can do this?
I'm using Oracle 11g.
You can get the dates into columns with pivot:
SELECT *
FROM (
SELECT M.EMAIL, R.LAST_OPEN_DATE,
ROW_NUMBER() OVER (PARTITION BY M.MEMBER_ID
ORDER BY R.LAST_OPEN_DATE DESC) AS RN
FROM MEMBER M, REPORT R
WHERE M.MEMBER_ID = R.MEMBER_ID
AND R.STATUS = 1
AND TRUNC(R.LAST_OPEN_DATE) >= TRUNC(SYSDATE) - 120
)
PIVOT (MIN(LAST_OPEN_DATE) FOR (RN) IN (1, 2, 3, 4, 5, 6, 7, 8));
SQL Fiddle.
Essentially this is assigning a number to each report date for each member, and then the pivot is based on that ranking number.
But you'd need to have each of the possible number of days listed; if you can have up to 240 report dates, the PIVOT IN clause would need to be every number up to 240, i.e. IN (1, 2, 3, ..., 239, 240), not just up to eight as in that Fiddle.
If you ever had a member with more than 240 dates you wouldn't see some of them, so whatever high number you pick would have to be high enough to cover every possibility, now and in the foreseeable future. As your query is limited to 120 days, even 240 seems quite high, but perhaps you have more than one per day - in which case there is no real upper limit.
You could potentially have to format each date column individually, but hopefully your reporting layer is taking care of that.
If you just wanted to perform string aggregation using the multiple dates for each email, in you could do this in 11g:
SELECT M.EMAIL,
LISTAGG(TO_CHAR(R.LAST_OPEN_DATE, 'DD/MM/YYYY'), ' ')
WITHIN GROUP (ORDER BY R.LAST_OPEN_DATE DESC)
FROM MEMBER M, REPORT R
WHERE M.MEMBER_ID = R.MEMBER_ID
AND R.STATUS = 1
AND TRUNC(R.LAST_OPEN_DATE) >= TRUNC(SYSDATE) - 120
GROUP BY M.EMAIL;
EMAIL DATES
-------------------- -------------------------------------------
email#1.com 12/04/2014 11/04/2014 10/04/2014 09/04/2014
email#2.com 12/05/2014 02/04/2014 22/03/2014 21/03/2014
SQL Fiddle.
Which is OK for a text report, but not if this query is feeding into a reporting tool.
First of all, number of columns in a query is determined before hand and can't be adjusted by the data. To overcome that, you might be interested in dynamic query
But, in simple static case, you will need to use PIVOT construction.
As a first step, you will need to assign rows to the columns
select EMAIL, row_number() over (partition by email order by last_date) col
from yourtable
then you add "magic" PIVOT:
<your query>
PIVOT
(
max(last_date)
for col in (1, 2, 3, ..., 240)
)
I have a row that is a varchar(50) that has a unique constraint and i would like to get the next unique number for an new insert but with a given prefix.
My rows could look like this:
ID (varchar)
00010001
00010002
00010003
00080001
So if I would like to get the next unqiue number from the prefix "0001" it would be "00010004" but if I would want it for the prefix "0008" it would be "00080002".
There will be more then 1 millon entries in this table. Is there a way with Oracle 11 to perform this kind of operation that is fairly fast?
I know that this setup is totaly insane but this is what I have to work with. I cant create any new tables etc.
You can search for the max value of the specified prefix and increment it:
SQL> WITH DATA AS (
2 SELECT '00010001' id FROM DUAL UNION ALL
3 SELECT '00010002' id FROM DUAL UNION ALL
4 SELECT '00010003' id FROM DUAL UNION ALL
5 SELECT '00080001' id FROM DUAL
6 )
7 SELECT :prefix || to_char(MAX(to_number(substr(id, 5)))+1, 'fm0000') nextval
8 FROM DATA
9 WHERE ID LIKE :prefix || '%';
NEXTVAL
---------
00010004
I'm sure you're aware that this is an inefficient method to generate a primary key. Furthermore it won't play nicely in a multi-user environment and thus won't scale. Concurrent inserts will wait then fail since there is a UNIQUE constraint on the column.
If the prefix is always the same length, you can reduce the workload somewhat: you could create a specialized index that would find the max value in a minimum number of steps:
CREATE INDEX ix_fetch_max ON your_table (substr(id, 1, 4),
substr(id, 5) DESC);
Then the following query could use the index and will stop at the first row retrieved:
SELECT id
FROM (SELECT substr(id, 1, 4) || substr(id, 5) id
FROM your_table
WHERE substr(id, 1, 4) = :prefix
ORDER BY substr(id, 5) DESC)
WHERE rownum = 1
If you need to do simultaneous inserts with the same prefix, I suggest you use DBMS_LOCK to request a lock on the specified newID. If the call fails because someone is already inserting this value, try with newID+1. Although this involves more work than traditional sequence, at least your inserts won't wait on each others (potentially leading to deadlocks).
This is a very unsatisfactory situation for you. As other posters have pointed out - if you don't use sequences then you will almost certainly have concurrency issues. I mentioned in a comment the possibility that you live with big gaps. This is the simplest solution but you will run out of numbers after 9999 inserts.
Perhaps an alternative would be to create a separate sequence for each prefix. This would only really be practical if the number of prefixes is fairly low but it could be done.
ps - your requirement that > 1000000 records should be possible may, in fact, mean you have no choice but to redesign the database.
SELECT to_char(to_number(max(id)) + 1, '00000000')
FROM mytable
WHERE id LIKE '0001%'
SQLFiddle demo here http://sqlfiddle.com/#!4/4f543/5/0
I would like to know that if I can compare a value with a list of items in an decode function. Basically I want to know that if is it possible to make a decode statement's 'search' value a list. For example,
decode(task_id, (1,2,3), 3 * task_time)
This piece of code won't compile though. Is this the only option for this case then (without using case-when) or are there alternative ways of doing this?
decode(task_id, 1, 3 * task_time,
2, 3 * task_time,
3, 3 * task_time)
I am using Oracle 10gR2. Any help is much appreciated.
If a single list of values is sufficient, you can turn it into a CASE and IN clause:
case when task_id in (1, 2, 3) then 3 * task_time else null end
I don't think its possible to use a list with decode in this way. Per the docs:
DECODE compares expr to each search value one by one. If expr is equal
to a search, then Oracle Database returns the corresponding result. If
no match is found, then Oracle returns default
So task_id is compared with a search value one by one. If search value was a list, you couldn't compare with a single value.
I found a solution :)
select
decode(
task_id,
(select task_id from dual where task_id in (1,2,3)),
3*task_time)
decode ( (taskid-1)*(taskid-2)*(taskid-3), 0, 3 * tasktime ) could do what you want
Here's a working example:
with a as (
select 1 taskid, 11 tasktime from dual union all
select 2 taskid, 11 tasktime from dual union all
select 3 taskid, 11 tasktime from dual union all
select 4 taskid, 11 tasktime from dual
)
select
taskid,
decode (
(taskid-1) *
(taskid-2) *
(taskid-3) ,
0, 3 * tasktime
) decoded
from a;
you can use union all:
select 3 * task_time from your_table where task_id in (1,2,3)
union all
select task_time from your_table where task_id not in (1,2,3)
but why ?
In if condition :
IF vVal in (3,1,2) THEN
dbms_output.put_line('FOUND');
ELSE
dbms_output.put_line('NOT FOUND');
END IF;
I've seen instr(...) and static strings used as a way to quickly determine whether a value is one of multiple you're looking for as a condition for what value you return. You may need to choose a delimiter, but with limited datasets you can even omit it. It avoids using case-when, subqueries, and PL/SQL. As far as I know, there is no shorter way to do this:
decode(instr('123', taskid), 0, null, taskid * 3)
It's also very convenient when you want to set exceptions (for instance returning taskid without multiplication if it equals 1):
decode(instr('12345', taskid), 0, null, 1, taskid, taskid * 3)