How to sort individual rows in descending order? - algorithm

I have a table which looks like the following:
Name LastName tPoints aPoints sPoints gPoints type
John Johnny 15 14 13 10 1
Joe P. 12 11 26 10 1
Matt Q. 11 26 37 44 2
Sorine P. 55 9 8 7 2
Ali Ahmed 30 44 88 65 2
... ... .. .. .. .. 3
3
I would like to sort INDIVIDUAL ROWS and display based on TYPE
NOTE: i can't use order by in oracle because it sorts only 1 row and the others
is sorted based on the first row
I don't want to break the table apart into individual tables, then sort it, and then update it back to the original table.
so, the output will looks something like this, for tPoints - i need to display all
15 - John Johnny
12 - Joe P.
and for aPoints
44 - Ali Ahmed
26 - Matt Q.
9 - Sorine P.
and so on ...
in a nutshell, if type = 1 then sort tPoints in descending, if type = 2 then sort aPoints, if type = 3 then sort sPoints, and so on....
what would be an efficient way to chive this?
Regards,

For the sake of simplicity this example includes only two types. Add as many types as you need.
SQL> with t1(Name1, LastName, tPoints, aPoints, sPoints, gPoints, type1) as(
2 select 'John' , 'Johnny', 15, 14, 13, 10, 1 from dual union all
3 select 'Joe' , 'P.' , 12, 11, 26, 10, 1 from dual union all
4 select 'Matt' , 'Q.' , 11, 26, 37, 44, 2 from dual union all
5 select 'Sorine', 'P.' , 55, 9 , 8 , 7, 2 from dual union all
6 select 'Ali' , 'Ahmed' , 30, 44, 88, 65, 2 from dual
7 )
8 select type1
9 , tpoints
10 , apoints
11 , name1
12 , Lastname
13 from t1
14 order by case when type1=1 then tpoints else type1 end desc,
15 case when type1=2 then apoints else type1 end desc;
TYPE1 TPOINTS APOINTS NAME1 LASTNAME
---------- ---------- ---------- ------ --------
1 15 14 John Johnny
1 12 11 Joe P.
2 30 44 Ali Ahmed
2 11 26 Matt Q.
2 55 9 Sorine P.

Related

Each row 3 column sum result show as running total in last column, then from 2nd row > first row running total show in first column with group by

Each row Total value go for the set OP value for the next row, except the first row
My Table Data
Id
WarehouseId
ProductId
OP
RE
IS
Total
1
100
10000
10
0
0
10
2
100
10000
0
0
5
5
4
100
10000
0
15
0
15
5
101
10001
15
0
0
15
6
101
10001
0
0
5
5
8
101
10001
0
15
0
15
9
101
10002
25
0
0
25
10
101
10002
0
0
10
10
11
101
10002
0
15
0
15
I want to show below result (OP+RE)-IS=Total
Id
WarehouseId
ProductId
OP
RE
IS
Total
1
100
10000
10
0
0
10
2
100
10000
10
0
5
5
4
100
10000
5
15
0
20
5
101
10001
15
0
0
15
6
101
10001
15
0
5
10
8
101
10001
10
15
0
25
9
101
10002
25
0
0
25
10
101
10002
25
0
10
15
11
101
10002
15
15
0
30
You can use recursive subquery factoring for that purpose like below. You need to rank your data as you have some gaps between IDs in your data. Column name = IS is not allowed, You should use "IS" enclosed by ".
with t1 ( ID, WAREHOUSEID, PRODUCTID, OP, RE, "IS", RNB, rnb_per_wh_prod) as (
select ID, WAREHOUSEID, PRODUCTID, OP, RE, "IS"
, row_number()over(order by WAREHOUSEID, PRODUCTID, ID) rnb
, row_number()over(partition by WAREHOUSEID, PRODUCTID order by ID) rnb_per_wh_prod
from Your_table t
), cte (ID, WAREHOUSEID, PRODUCTID, OP, RE, "IS", Total, RNB) as (
select ID, WAREHOUSEID, PRODUCTID, OP, RE, "IS", OP + RE - "IS", RNB
from t1
where rnb_per_wh_prod = 1
union all
select t1.ID
, t1.WAREHOUSEID
, t1.PRODUCTID
, case when t1.op = 0 then c.OP + c.RE - c."IS" else t1.OP end as OP
, t1.RE
, t1."IS"
, case when t1.op = 0 then c.OP + c.RE - c."IS" else t1.OP end + t1.RE - t1."IS" total
, t1.RNB
from cte c
join t1 on (t1.RNB = c.RNB + 1
and c.WAREHOUSEID = t1.WAREHOUSEID
and c.PRODUCTID = t1.PRODUCTID)
)
select ID, WAREHOUSEID, PRODUCTID, OP, RE, "IS", TOTAL
from cte
order by id
;
If I understand the problem correctly, "every 3 row" is a coincidence in your data; in fact, the computation must be done separately for each product in each warehouse, no matter how many rows there are for each distinct combination. And the "id" column is in reality some sort of timestamp - ordering is by "id".
If so, you can do it all in a single query using analytic sum(). Instead of creating a table for testing, I included all the sample data in a WITH clause at the top of the query itself; you can remove the WITH clause, and use your actual table and column names. I also changed the column name is to is_ since is is a reserved keyword, it can't be a column name.
Note also that I am ignoring your existing total column completely (I didn't even include it in the sample data); I assume it doesn't exist in your real-life data, and instead it is part of your attempt at a solution. You don't need it - not in the way you have it in your question.
with
sample_data (id, warehouseid, productid, op, re, is_) as (
select 1, 100, 10000, 10, 0, 0 from dual union all
select 2, 100, 10000, 0, 0, 5 from dual union all
select 4, 100, 10000, 0, 15, 0 from dual union all
select 5, 101, 10001, 15, 0, 0 from dual union all
select 6, 101, 10001, 0, 0, 5 from dual union all
select 8, 101, 10001, 0, 15, 0 from dual union all
select 9, 101, 10002, 25, 0, 0 from dual union all
select 10, 101, 10002, 0, 0, 10 from dual union all
select 11, 101, 10002, 0, 15, 0 from dual
)
select id, warehouseid, productid,
nvl(sum(op + re - is_) over (partition by warehouseid, productid
order by id rows between unbounded preceding and 1 preceding),
op) as op,
re, is_,
sum(op + re - is_) over
(partition by warehouseid, productid order by id) as total
from sample_data
;
ID WAREHOUSEID PRODUCTID OP RE IS_ TOTAL
------ ----------- ---------- ---------- ---------- ---------- ----------
1 100 10000 10 0 0 10
2 100 10000 10 0 5 5
4 100 10000 5 15 0 20
5 101 10001 15 0 0 15
6 101 10001 15 0 5 10
8 101 10001 10 15 0 25
9 101 10002 25 0 0 25
10 101 10002 25 0 10 15
11 101 10002 15 15 0 30

Want to convert rows to columns

I have one table t as below
Customer _no | receipt_no
----------------------------
A | 123
A. | 234
A. | 345
B. | 465
B. | 675
I want result as
Customer _no | receipt_1 | receipt_2
A. | 123. | 234
A. | 345. | Null
B. | 465. | 675
Please suggest how to do this
If I understood it correctly, you want to have two columns for each customer. If that's so, here's one option.
SQL> with test (cno, rno) as
2 (select 'A', 123 from dual union all
3 select 'A', 234 from dual union all
4 select 'A', 345 from dual union all
5 select 'A', 444 from dual union all
6 select 'A', 555 from dual union all
7 select 'B', 456 from dual union all
8 select 'B', 675 from dual
9 ),
10 inter as
11 (select cno, rno,
12 row_number() over (partition by cno order by cno, rno) rn,
13 round(row_number() over (partition by cno order by cno, rno) /2) grp
14 from test
15 )
16 select cno,
17 max(decode(mod(rn, 2), 1, rno)) r1,
18 max(decode(mod(rn, 2), 0, rno)) r2
19 from inter
20 group by cno, grp
21 order by cno, grp;
C R1 R2
- ---------- ----------
A 123 234
A 345 444
A 555
B 456 675
SQL>

Order by query results in specific row positions

This is an extension to a previous quesiton, Order by depending on 2 col values. I have a query which returns the output as below,
SELECT DISTINCT a.rev_date ,fruitname,
fruit_id , primary_fruit_id
FROM fruits a, fruit_lookup s,fruit_reference r
WHERE a.id = s.id(+)
and primary_fruit_id = r.fruit_id(+)
AND (fruit_id = 24 or fruit_id = 0)
ORDER BY case when fruit_id = primary_fruit_id then 0 else 1 end,
fruit_id desc,
a.rev_date desc
How to handle this such that I get the desired output in the below fashion. So, where ever the fruit_id is 0, those rows need to go in the 2nd and the 5th row in the result set of say 10 rows. If totals results are around 50, each page will have 10 results, and in 2nd and the 5th position I need to get the output as below. Hope this makes sense. Any ideas are appreciated. thx
NAME FRUIT_ID PRIMARY_FRUIT_ID
--------------------------------------
apple 24 24
apple 24 24
apple 24 24
apple 24 24
orange 24 12
pear 24 7
kiwi 24 6
melon 24 2
grape 0 90
banana 0 45
carrot 0 30
Desired output
NAME FRUIT_ID PRIMARY_FRUIT_ID
--------------------------------------
apple 24 24
grape 0 90
apple 24 24
apple 24 24
banana 0 45
apple 24 24
kiwi 24 6
orange 24 12
melon 24 2
pear 24 7
carrot 0 30
This is much more complicated question than your previous, so answer is somewhat complicated too.
Here is something what I managed to do:
with t as (
select x.*,
row_number() over (
partition by fid order by decode(fid , pfid, 1, 2), rd desc) rbr
from (
select distinct a.rev_date rd, s.fruitname fn,
a.fruit_id fid, primary_fruit_id pfid
from fruits a left join fruit_lookup s on a.id = s.id
left join fruit_reference r
on primary_fruit_id = r.fruit_id and r.fruit_id in (0, 24) ) x),
ca as (select count(1) cnt from t),
cx as (
select row_number() over (partition by cwm order by lvl) rn, cwm, lvl
from (
select level lvl, case when mod(level, 10) in (2, 5) then 0 else 24 end cwm
from ca connect by level <= cnt*5))
select rd, fn, fid, pfid
from t join cx on cx.rn = t.rbr and cx.cwm = t.fid
order by lvl
You did not provide data structures and sample rows, so I tried to reproduce them to get original input, here is SQLFiddle with data and query.
Subquery cx generates numbers, according to your rules, then these numbers are assigned to your original query
and final select sorts data using these numbers.
The general logic is: insert rows with fruit_id=0 numbered as 2, 5, 12, 15, 22... between other rows.

Oracle Sql query to count time span with certain criteria

Oracle Sql query , I was trying to count the grand total for time difference that is greater than 2, but when I tried this it just counted all the rows from the query instead of just the rows that have the criteria I was looking for. Anybody have an idea of what I am missing or a better approach . Thanks
This is my query
select DC.CUST_FIRST_NAME,DC.CUST_LAST_NAME,oi.customer_id,oi.order_timestamp,oi.order_timestamp - LAG(oi.order_timestamp) OVER (ORDER BY oi.order_timestamp) AS "Difference(In Days)" ,
(select Count('Elapsed Order Difference')
from demo_orders oi,
demo_customers dc
where OI.CUSTOMER_ID = DC.CUSTOMER_ID
group by 'Elapsed Order Difference'
having count('Elapsed Order Difference') > 3
)Total
from demo_orders oi,
demo_customers dc
where OI.CUSTOMER_ID = DC.CUSTOMER_ID
Results
CUST_FIRST_NAME CUST_LAST_NAME CUSTOMER_ID ORDER_TIMESTAMP Difference(In Days) TOTAL
Eugene Bradley 7 8/14/2013 5:59:11 PM 10
William Hartsfield 2 8/28/2013 5:59:11 PM 14 10
Edward "Butch" OHare 4 9/8/2013 5:59:11 PM 11 10
Edward Logan 3 9/10/2013 5:59:11 PM 2 10
Edward Logan 3 9/20/2013 5:59:11 PM 10 10
Albert Lambert 6 9/25/2013 5:59:11 PM 5 10
Fiorello LaGuardia 5 9/30/2013 5:59:11 PM 5 10
William Hartsfield 2 10/8/2013 5:59:11 PM 8 10
John Dulles 1 10/14/2013 5:59:11 PM 6 10
Eugene Bradley 7 10/17/2013 5:59:11 PM 3 10
This is untested, but I think it might give you what you're after.
with raw_data as (
select
dc.cust_first_name, dc.cust_last_name,
oi.customer_id, oi.order_timestamp,
oi.order_timestamp - LAG(oi.order_timestamp) OVER
(ORDER BY oi.order_timestamp) AS "Difference(In Days)",
case
when oi.order_timestamp - LAG(oi.order_timestamp)
over (ORDER BY oi.order_timestamp) > 2 then 1
else 0
end as gt2
from
demo_orders oi,
demo_customers dc
where
oi.customer_id = dc.customer_id
)
select
cust_first_name, cust_last_name,
customer_id, order_timestamp,
"Difference(In Days)",
sum (gt2) over (partition by 1) as total
from raw_data
When you do Count('Elapsed Order Difference') above, you are counting every row, no matter what. You could have put count ('frog') or count (*) and have gotten the same result. The having count > 3 was already satisfied since the count of all rows was 10.
In general, I'd try to avoid using a scalar for a field in a query as you have in your example. I'm not saying it's never a good idea, but I would argue that there is usually a better way to do it. With 10 rows, you'll hardly notice a performance difference, but as your datasets grow, this can create issues.
Expected output:
fn ln id order date dif total
E B 7 8/14/2014 8
W H 2 8/28/2014 14 8
E O 4 9/8/2014 11 8
E L 3 9/10/2014 2 8
E L 3 9/20/2014 10 8
A L 6 9/25/2014 5 8
F L 5 9/30/2014 5 8
W H 2 10/8/2014 8 8
J D 1 10/14/2014 6 8
E B 7 10/17/2014 3 8

Oracle7:Merge data are same in many records to one record

I would like to merge data are same in many records to one record.
From
FO LINE FLOOR COLOR SUM
S4714EH02 EH 11F AK 9
S4714EH02 EH 11F AK 18
S4714EH02 EH 11F FE 9
S4714EH02 EH 11F FE 18
S4714EH02 EH 12F AK 9
S4714EH02 EH 12F AK 18
S4714EH02 EH 12F FE 9
S4714EH02 EH 12F FE 18
To
FO LINE FLOOR COLOR SUM
S4714EH02 EH 11F AK 9,18
S4714EH02 EH 11F FE 9,18
S4714EH02 EH 12F AK 9,18
S4714EH02 EH 12F FE 9,18
I know it can in sql server 2008 but I don't know it can make in oracle7 .
Please help me. Thank you.
Oracle 7 is a fine release of that database. it introduced many new features, it performed well and obviously it remains exceedingly stable. But it is long in the tooth and lacks many features available to us in more recent versions of the product.
For instance, all of the normal techniques we can use to aggregate values into a list only work in 9i or higher. (Some may work in 8i, my mind is a little fuzzy here as it's been almost a decade since I worked with Oracle that old)
So do you have any options in Oracle 7? The only one I can think of is to run a stored procedure as part of a reporting pre-process. This stored procedure would loop round the rows you want to query, assemble rows which matched your desired output and then insert them into a different table. This table would then service the actual query.
This is an extremely clunky workaround, and may not be viable in your situation. But alas that is the cost of using legacy software.
As already very well said by APC, this version is really old and lacks all kinds of functions to do string aggregation. I have worked with version 7 in the previous millenium though, and I think the next sequence should work in Oracle7. I could be wrong though, but obviously I can't check it.
SQL> create table t (fo,line,floor,color,sum)
2 as
3 select 'S4714EH02', 'EH', '11F', 'AK', 9 from dual union all
4 select 'S4714EH02', 'EH', '11F', 'AK', 18 from dual union all
5 select 'S4714EH02', 'EH', '11F', 'FE', 9 from dual union all
6 select 'S4714EH02', 'EH', '11F', 'FE', 18 from dual union all
7 select 'S4714EH02', 'EH', '12F', 'AK', 9 from dual union all
8 select 'S4714EH02', 'EH', '12F', 'AK', 18 from dual union all
9 select 'S4714EH02', 'EH', '12F', 'FE', 9 from dual union all
10 select 'S4714EH02', 'EH', '12F', 'FE', 18 from dual
11 /
Table created.
SQL> create function f
2 ( p_fo in t.fo%type
3 , p_line in t.line%type
4 , p_floor in t.floor%type
5 , p_color in t.color%type
6 ) return varchar2
7 is
8 cursor c
9 is
10 select t.sum
11 from t
12 where t.fo = p_fo
13 and t.line = p_line
14 and t.floor = p_floor
15 and t.color = p_color
16 order by t.sum
17 ;
18 l_concatenated_sum varchar2(2000);
19 begin
20 for r in c
21 loop
22 l_concatenated_sum := l_concatenated_sum || ',' || to_char(r.sum);
23 end loop;
24 return substr(l_concatenated_sum,2);
25 end f;
26 /
Function created.
SQL> select fo
2 , line
3 , floor
4 , color
5 , f(fo,line,floor,color) sum
6 from t
7 group by fo
8 , line
9 , floor
10 , color
11 /
FO LI FLO CO SUM
--------- -- --- -- --------------------
S4714EH02 EH 11F AK 9,18
S4714EH02 EH 11F FE 9,18
S4714EH02 EH 12F AK 9,18
S4714EH02 EH 12F FE 9,18
4 rows selected.
Regards,
Rob.
In the special case where you have only two records per distinct key -- as shown by your sample data -- you could do this:
SELECT fo, line, floor, color, MIN(sum) || ',' || MAX(sum)
FROM theTable
GROUP BY fo, line, floor, color;
But this can't be generalized to handle more than two values of sum per key.

Resources