Second method for getting output using SQL query in ORACLE - sql

I have a table which has data as:
My expected output is:
I got my expected output as using rownum:
SELECT ID,PRICE FROM OT.TEST1 WHERE ROWNUM<3;
It's working finesince i have inserted the data serially as the output is coming with rownum ,but what,if the data were inserted as random below,my rownum will not work.Is there any new method?
ID PRice
3 300
3 600
8 600
2 600

You could use ROW_NUMBER() here:
WITH cte AS (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY PRICE, ID) rn
FROM OT.TEST1 t
)
SELECT ID, PRICE
FROM cte
WHERE rn <= 2;
Here we are assigning a row number over the entire table ordered first by price ascending, and then by ID. Since three records are tied for a price of 600, the record with the lowest ID would happen to be returned here.

Related

Teradata SQL - How to transpose data in one row

I have a table as below:
I currently have a query that selects records where SEQ=450 and RESULT='LT' OR SEQ=650 and RESULT='LT'. And for a particular ID, if there are both Sequences with 450 and 650 with RESULT='LT' like in this case as shown, I only keep the row with SEQ=450 and RESULT='LT'. However, what I want as a final output is also the SEQ and CODE values from the row above the 450 SEQ. like below
and if only 650 exists for an ID then,
Obviously in this case I would only choose seq=450.
The current query I have is
CREATE MULTISET VOLATILE TABLE DOM AS (
WITH cte AS (
SELECT DISTINCT ID
FROM MASTER
WHERE SEQ = 450
)
SELECT DISTINCT SCAN.ID, SCAN.SEQ, SCAN.CODE, SCAN.RESULT FROM MASTER
WHERE (MASTER.SEQ = 450 OR (MASTER.SEQ = 650 AND NOT EXISTS (
SELECT 1 FROM cte WHERE cte.ID = MASTER.ID AND cte.ID = MASTER.ID
))) AND MASTER.RESULT ='LT'
) WITH DATA PRIMARY INDEX (ID, SEQ) ON COMMIT PRESERVE ROWS;
Which gives me the output for this particular ID as:
How can I modify the query to also get the
other columns? Note: The SEQ_BEFORE will not always be 300 or 600, so I cannot just use that seq no. as a reference in the query.
This is how I understand the task: You want to get the data for seq 450 and 650 along with their predecessor values (seq 300 and 600 in your example) Then per ID you only want to select the row with the lesser ID of the two, so if you find only one of the two sequences 450 and 650, you show it, if there exist both, you only show 450.
Use LAG to get the predecessor's values. Use MIN OVER to get the lesser seq per ID.
select *
from
(
select
id, seq, result, code,
lag(code) over (partition by id order by seq) as code_before,
lag(seq) over (partition by id order by seq) as seq_before
from mytable
) with_values_before
where seq in (450, 650)
qualify seq = min(seq) over (partition by id)
order by id;

Use window functions to select the value from a column based on the sum of another column, in an aggregate query

Consider this data (View on DB Fiddle):
id
dept
value
1
A
5
1
A
5
1
B
7
1
C
5
2
A
5
2
A
5
2
B
15
2
A
2
The base query I am running is pretty simple. Just get the total value by id and the most frequent dept.
SELECT
id,
MODE() WITHIN GROUP(ORDER BY dept) AS dept_freq,
SUM(value) AS value
FROM test
GROUP BY id
;
id
dept_freq
value
1
A
22
2
A
27
But I also need to get, for each id, the dept that concentrates the greatest value (so the greatest sum of value by id and dept, not the highest individual value in the original table).
Is there any way to use window functions to achieve that and do it directly in the base query above?
The expected output for this particular example would be:
id
dept_freq
dept_value
value
1
A
A
22
2
A
B
27
I could achieve that with the query below and then joining that with the results of the base query above
SELECT * FROM(
SELECT
*,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY value DESC) as row
FROM (
SELECT id, dept, SUM(value) AS value
FROM test
GROUP BY id, dept
) AS alias1
) AS alias2
WHERE alias2.row = 1
;
id
dept
value
row
1
A
10
1
2
B
15
1
But it is not easy to read/maintain and seems also pretty inefficient. So I thought it should be possible to achieve this using window functions directly in the base query, and that also may also help Postgres to come up with a better query plan that does less passes over the data. But none of my attempts using over partition and filter worked.
step-by-step demo:db<>fiddle
You can fetch the dept for the highest values using the first_value() partition function. Adding this before your mode() grouping should do it:
SELECT
id,
highest_value_dept,
MODE() WITHIN GROUP(ORDER BY dept) AS dept_freq,
SUM(value) as value
FROM (
SELECT
id,
dept,
value,
FIRST_VALUE(dept) OVER (PARTITION BY id ORDER BY value DESC) as highest_value_dept
FROM test
) s
GROUP BY 1,2

How to get nth record in a sql server table without changing the order?(sql server)

for example i have data like this(sql server)
id name
4 anu
3 lohi
1 pras
2 chand
i want 2nd record in a table (means 3 lohi)
if i use row_number() function its changes the order and i get (2 chand)
i want 2nd record from table data
can anyonr please give me the query fro above scenario
There is no such thing as the nth row in a table. And for a simple reason: SQL tables represent unordered sets (technically multi-sets because they allow duplicates).
You can do what you want use offset/fetch:
select t.*
from t
order by id desc
offset 1 fetch first 1 row only;
This assumes that the descending ordering on id is what you want, based on your example data.
You can also do this using row_number():
select t.*
from (select t.*,
row_number() over (order by id desc) as seqnum
from t
) t
where seqnum = 2;
I should note that that SQL Server allows you to assign row_number() without having an effective sort using something like this:
select t.*
from (select t.*,
row_number() over (order by (select NULL)) as seqnum
from t
) t
where seqnum = 2;
However, this returns an arbitrary row. There is no guarantee it returns the same row each time it runs, nor that the row is "second" in any meaningful use of the term.

Get every second row as a result table in t-sql

I'm looking for a t-sql script that returns a list, that shows every second value from a grouping from Table1.
For example I have the following data (Table1) and want the desired result-list:
Table1:
Customer Quantity
A 5
A 8 (*)
B 3
B 5 (*)
B 11
C 7
D 4
D 23 (*)
Desired retult-list:
Customer Quantity
A 8
B 5
D 23
I think about doing something something with 'select distinct and left outer join', but I can't get it to work. Possibly I need an row numbering, but can't figure out how to do it. Anyone can help me?
Beneath is the script I used to make and fill Table1:
CREATE TABLE Table1
(Customer nvarchar(1) NULL,
Quantity int NOT NULL);
INSERT INTO Table1(Customer,Quantity)
VALUES
('A',5),
('A',8),
('B',3),
('B',5),
('B',11),
('C',7),
('D',4),
('D',23);
This can be done quite easily using the row_number window function:
SELECT customer, quantity
FROM (SELECT customer, quantity,
ROW_NUMBER() OVER (PARTITION BY customer
ORDER BY quantity ASC) AS rn
FROM table1) t
WHERE rn = 2
You can use ROW_NUMBER and a CTE:
WITH data AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY Quantity) rn
FROM #Table1
)
SELECT Customer, Quantity
FROM data
WHERE rn = 2
How it works:
Using ROW_NUMBER() will assign a sequential number to each row based on what's specified in OVER (). In OVER i specify to PARTITION the rows on customer, that means each group of data on same customer will be numberered separately. Then ORDER BY Quantity mean it should order the data based on quantity for each customer - so i can get the 2nd row for each customer ordered by quantity.

Selecting the newest records for 6 unique columns

I have a table of 6 currency conversions, it's updated almost daily. Unfortunately the way the software works is it inserts new rows rather than updating the existing ones. My previous SELECT was as follows
SELECT FROM_CURRENCY_ID, XCHG_RATE
FROM
(
SELECT TOP 6 FROM_CURRENCY_ID, XCHG_RATE
FROM SHARED_CURRENCY_EXCHANGE
WHERE NOT FROM_CURRENCY_ID = 'CAD'
ORDER BY RECORD_CREATED desc
) t
ORDER BY FROM_CURRENCY_ID
The issue now is some records got updated while others didn't so my query returns duplicate values for one of the currencys and nothing for one. I need it to output the 6 unique FROM_CURRENCY_IDs and their XCHG_RATE with the newest RECORD_CREATED dates
I've been trying a group by to exclude the duplicate rows with no luck.
with x as
(select row_number() over(partition by from_currency_id order by record_created desc) rn, * from shared_currency_exchange)
select from_currency_id, xchg_rate from x
where rn = 1
This gives the most recent record a rownumber 1 and you can use the cte with this condition.