Is there a way to combine the results of queries on two unrelated tables - oracle-sqldeveloper

A quick question:
I have results from two SQL Queries,
The first one queries for a column named as svb_rate for the CURRENT_DATE from a particular table named as ODS.PS_RT_RATE_TBL
The second one queries for a column named as PRINCIPAL_BAL_NET from another table named as FRDS_LOANS_MV
My aim is to multiply these two columns and get the results in a new column.
The main problem is that the two tables mentioned above are unrelated, hence we will not be able to execute joins, to my knowledge.
I considered using cross joins, but I am not sure it would work.
Is there a way to get the required answer, or is it not possible.
Please do let me know.
Thanks.

Just a few thoughts about your question. Without sample data it is impossible to give an answer. So, if we put that sample data like below (just for testing):
PS_RT_RATE_TBL
A_DATE
SVB_RATE
27-DEC-22
2.5
28-DEC-22
1.75
29-DEC-22
1.5
30-DEC-22
1.38
31-DEC-22
1.3
FRDS_LOANS_MV
LOAN_ID
PRINCIPAL_BAL_NET
1
999.45
2
998.83
3
998.15
1. CROSS JOIN
If there is a table with 5 rows and another with 3 rows we will get 15 rows as a resulting dataset
Select r.A_DATE, r.SVB_RATE, l.PRINCIPAL_BAL_NET, l.LOAN_ID
From PS_RT_RATE_TBL r
Cross Join FRDS_LOANS_MV l
Order By l.LOAN_ID, r.A_DATE
Doesn't look very usefull - not knowing what you need, though
A_DATE
SVB_RATE
PRINCIPAL_BAL_NET
LOAN_ID
27-DEC-22
2.5
999.45
1
28-DEC-22
1.75
999.45
1
29-DEC-22
1.5
999.45
1
30-DEC-22
1.38
999.45
1
31-DEC-22
1.3
999.45
1
27-DEC-22
2.5
998.83
2
28-DEC-22
1.75
998.83
2
29-DEC-22
1.5
998.83
2
30-DEC-22
1.38
998.83
2
31-DEC-22
1.3
998.83
2
27-DEC-22
2.5
998.15
3
28-DEC-22
1.75
998.15
3
29-DEC-22
1.5
998.15
3
30-DEC-22
1.38
998.15
3
31-DEC-22
1.3
998.15
3
2. PIVOT
The above cross joined data could be pivoted
SELECT *
FROM ( Select r.A_DATE, r.SVB_RATE, l.PRINCIPAL_BAL_NET, l.LOAN_ID
From PS_RT_RATE_TBL r
Cross Join FRDS_LOANS_MV l
Order By l.LOAN_ID, r.A_DATE
)
PIVOT (
Count(A_DATE) "DAYS", Avg(SVB_RATE) "AVG_RATE", Min(PRINCIPAL_BAL_NET) "BAL_NET"
For LOAN_ID In(1 "ID_1", 2 "ID_2", 3 "ID_3")
)
Still looks odd and not saying much...
ID_1_DAYS
ID_1_AVG_RATE
ID_1_BAL_NET
ID_2_DAYS
ID_2_AVG_RATE
ID_2_BAL_NET
ID_3_DAYS
ID_3_AVG_RATE
ID_3_BAL_NET
5
1.686
999.45
5
1.686
998.83
5
1.686
998.15
3. UNPIVOT
SELECT *
FROM
(SELECT *
FROM (Select r.A_DATE, r.SVB_RATE, l.PRINCIPAL_BAL_NET, l.LOAN_ID
From PS_RT_RATE_TBL r
Cross Join FRDS_LOANS_MV l
Order By l.LOAN_ID, r.A_DATE
)
PIVOT (
Count(A_DATE) "DAYS", Avg(SVB_RATE) "AVG_RATE", Min(PRINCIPAL_BAL_NET) "BAL_NET"
For LOAN_ID In(1 "ID_1", 2 "ID_2", 3 "ID_3")
)
)
UNPIVOT (
( AVG_RATE, BAL_NET, DAYS)
For ID
IN( ( ID_1_AVG_RATE, ID_1_BAL_NET, ID_1_DAYS) As 1,
( ID_2_AVG_RATE, ID_2_BAL_NET, ID_2_DAYS) As 2,
( ID_3_AVG_RATE, ID_3_BAL_NET, ID_3_DAYS) As 3
)
)
Well, even if it doesn't help - it looks nicer now...
ID
AVG_RATE
BAL_NET
DAYS
1
1.686
999.45
5
2
1.686
998.83
5
3
1.686
998.15
5
You can do your own pivoting and unpivoting - this is just to give you some options to think about and, as such, just an example on imaginary sample data.
NOTE: You can do multiplication of your columns in any of above 3 steps.

Related

PostgreSQL group by and count on specific condition

I have the following tables (example)
Analyze_Line
id
game_id
bet_result
game_type
1
1
WIN
0
2
2
LOSE
0
3
3
WIN
0
4
4
LOSE
0
5
5
LOSE
0
6
6
WIN
0
Game
id
league_id
home_team_id
away_team_id
1
1
1
2
2
2
2
3
3
3
3
4
4
1
1
2
5
2
2
3
6
3
3
4
Required Data:
league_id
WIN
LOSE
GameCnt
1
1
1
2
2
0
2
2
3
2
0
2
The Analyze_Line table is joined with the Game table and simple can get GameCnt grouping by league_id, but I am not sure how to calculate WIN count and LOSE count in bet_result
You can use conditionals in aggregate function to divide win and lose bet results per league.
select
g.league_id,
sum(case when a.bet_result = 'WIN' then 1 end) as win,
sum(case when a.bet_result = 'LOSE' then 1 end) as lose,
count(*) as gamecnt
from
game g
inner join analyze_line a on
g.id = a.game_id
group by
g.league_id
Since there is no mention of postgresql version, I can't recommend using FILTER clause (postgres specific), since it might not work for you.
Adding to Kamil's answer - PostgreSQL introduced the filter clause in PostgreSQL 9.4, released about eight years ago (December 2014). At this point, I think it's safe enough to use in answers. IMHO, it's a tad more elegant than summing over a case expression, but it does have the drawback of being PostgreSQL specific syntax, and thus not portable:
SELECT g.league_id,
COUNT(*) FILTER (WHERE a.bet_result = 'WIN') AS win,
COUNT(*) FILTER (WHERE a.bet_result = 'LOSE') AS lose,
COUNT(*) AS gamecnt
FROM game g
JOIN analyze_line a ON g.id = a.game_id
GROUP BY g.league_id

SQL Select based on each row of previous select

I have a table with answers regarding different questions, all of them numbered. There are basically these columns: IdAnswer (unique for each answer in the table), IdUser (which won't repeat even if the same user answer questions a second time), IdQuestion and Answer.
IdAnswer IdUser IdQuestion Answer
1 John 1 0
2 John 4 1
3 John 5 1
4 John 6 0
5 Bob 1 1
6 Bob 3 1
7 Bob 5 0
8 Mark 2 0
9 Mark 7 1
10 Mark 5 0
I'd like to select from this table all answers to a specific question (say, IdQuestion = 5), and also the last question each user answered just before question number 5.
In the end I need a table that should look like this:
IdAnswer IdUser IdQuestion Answer
2 John 4 1
3 John 5 1
6 Bob 3 1
7 Bob 5 0
9 Mark 7 1
10 Mark 5 0
I've managed to make this work using a cursor to iterate through each line from the first SELECT result (which filters by IdQuestion), but I'm not sure if this is the best (and fastest) way of doing it. Is there any more efficient way of achieving the same result?
And by the way, I'm using SQL Server Management Studio 2012.
Here is one way using LEAD function
select * from
(
select *,NextQ = Lead(IdQuestion)over(partition by IdUser order by IdAnswer)
from youtable
) a
Where 5 in (IdQuestion, NextQ )
for older versions
;WITH cte
AS (SELECT prev_id = Min(CASE WHEN IdQuestion = 5 THEN rn - 1 END) OVER( partition BY IdUser),*
FROM (SELECT rn = Row_number()OVER(partition BY IdUser ORDER BY IdAnswer),*
FROM Yourtable)a)
SELECT *
FROM cte
WHERE rn IN ( prev_id, prev_id + 1 )

combining results of CTEs

I have several CTEs. CTE1A counts number of type A shops in area 1. CTE1B counts number of type B shops in area 1 and so on up to CTE1D. Similarly, CTE2B counts number of type B shops in area 2 and so on. shop_types CTE selects all types of shops: A,B,C,D. How to display a table that shows for each area (column) how many shops of each type there is (rows).
For example:
1 2 3 4 5
A 0 7 4 0 0
B 2 3 8 2 9
C 8 5 8 1 6
D 7 1 5 4 3
Database has 2 tables:
Table regions: shop_id, region_id
Table shops: shop_id, shop_type
WITH
shop_types AS (SELECT DISTINCT shops.shop_type AS type FROM shops WHERE shops.shop_type!='-9999' AND shops.shop_type!='Other'),
cte1A AS (
SELECT regions.region_id, COUNT(regions.shop_id) AS shops_number, shops.shop_type
FROM regions
RIGHT JOIN shops
ON shops.shop_id=regions.shop_id
WHERE regions.region_id=1
AND shops.shop_type='A'
GROUP BY shops.shop_type,regions.region_id)
SELECT * FROM cte1A
I'm not entirely sure I understand why you are after, but it seems you are looking for something like this:
select sh.shop_type,
count(case when r.region_id = 1 then 1 end) as region_1_count,
count(case when r.region_id = 2 then 1 end) as region_2_count,
count(case when r.region_id = 3 then 1 end) as region_3_count
from shops sh
left join regions r on r.shop_id = sh.shop_id
group by sh.shop_type
order by sh.shop_type;
You need to add one case statement for each region you want to have in the output.
If you are using Postgres 9.4 you can replace the case statements using a filter condition which kind of makes the intention a bit easier to understand (I think)
count(*) filter (where r.region_id = 1) as region_1_count,
count(*) filter (where r.region_id = 2) as region_2_count,
...
SQLFiddle: http://sqlfiddle.com/#!1/98391/1
And before you ask: no you can't make the number of columns "dynamic" based on a select statement. The column list for a query must be defined before the statement is actually executed.

How to optimize query

I have the same problem as mentioned in In SQL, how to select the top 2 rows for each group. The answer is working fine. But it takes too much time. How to optimize this query?
Example:
sample_table
act_id: act_cnt:
1 1
2 1
3 1
4 1
5 1
6 3
7 3
8 3
9 4
a 4
b 4
c 4
d 4
e 4
Now i want to group it (or using some other ways). And i want to select 2 rows from each group. Sample Output:
act_id: act_cnt:
1 1
2 1
6 3
7 3
9 4
a 4
I am new to SQL. How to do it?
The answer you linked to uses an inefficient workaround for MySQL's lack of window functions.
Using a window function is most probably much faster as you only need to read the table once:
select name,
score
from (
select name,
score,
dense_rank() over (partition by name order by score desc) as rnk
from the_table
) t
where rnk <= 2;
SQLFiddle: http://sqlfiddle.com/#!15/b0198/1
Having an index on (name, score) should speed up this query.
Edit after the question (and the problem) has been changed
select act_id,
act_cnt
from (
select act_id,
act_cnt,
row_number() over (partition by act_cnt order by act_id) as rn
from sample_table
) t
where rn <= 2;
New SQLFiddle: http://sqlfiddle.com/#!15/fc44b/1

Multi-Column, Multi-Row PIVOT

Consider that I have a table which contains data in the following form:
Foo_FK MonthCode_FK Activity_FK SumResultsX SumResultsY
-----------------------------------------------------------
1 201312 0 10 2
1 201312 1 5 1
1 201401 0 15 3
1 201401 1 7 2
2 201312 0 9 3
2 201312 1 1 2
2 201401 0 6 2
2 201401 1 17 4
For my purposes, it is safe to assume that this table is an aggregation which would have been created by a GROUP BY on Foo_FK, MonthCode_FK, Activity_FK with SUM( ResultsA ), SUM( ResultsB ) to obtain the data, making Foo_FK, MonthCode_FK, Activity_FK unique per record.
If for some reason I found it preferable to PIVOT this table in a stored procedure to ease the amount of screwing around with SSRS I'd have to do ( and undoubtedly later maintain ), wishing to get the following format for consumption via a matrix tablix thingy:
Foo_FK 1312_0_X 1312_0_Y 1312_1_X 1312_1_Y 1401_0_X 1401_0_Y 1401_1_X 1401_1_Y
--------------------------------------------------------------------------------------
1 10 2 5 1 15 3 7 2
2 9 3 1 2 6 2 17 4
How would I go about doing this in a not-mental way? Please refer to this SQL Fiddle at proof I am likely trying to use a hammer to build a device that pushes in nails. Don't worry about a dynamic version as I'm sure I can figure that out once I'm guided through the static solution for this test case.
Right now, I've tried to create a Foo_FK, MonthCode_FK set via the following, which I then attempt to PIVOT ( see the Fiddle for the full mess ):
SELECT Foo_FK = ISNULL( a0.Foo_FK, a1.Foo_FK ),
MonthCode_FK = ISNULL( a0.MonthCode_FK, a1.MonthCode_FK ),
[0_X] = ISNULL( a0.SumResultX, 0 ),
[0_Y] = ISNULL( a0.SumResultY, 0 ),
[1_X] = ISNULL( a1.SumResultX, 0 ),
[1_Y] = ISNULL( a1.SumResultY, 0 )
FROM ( SELECT Foo_FK, MonthCode_FK, Activity_FK,
SumResultX, SumResultY
FROM dbo.t_FooActivityByMonth
WHERE Activity_FK = 0 ) a0
FULL OUTER JOIN (
SELECT Foo_FK, MonthCode_FK, Activity_FK,
SumResultX, SumResultY
FROM dbo.t_FooActivityByMonth
WHERE Activity_FK = 1 ) a1
ON a0.Foo_FK = a1.Foo_FK;
I have come across some excellent advice on this SO question, so I'm in the process of performing some form of UNPIVOT before I twist everything back out using PIVOT and MAX, but if there's a better way to do this, I'm all ears.
It seems that you should be able to do this by applying unpivot to your SumResultX and SumResultY columns first, then pivoting the data:
;with cte as
(
select Foo_FK,
col = cast(MonthCode_FK as varchar(6))+'_'
+cast(activity_fk as varchar(1))+'_'+sumresult,
value
from dbo.t_FooActivityByMonth
cross apply
(
values
('X', SumResultX),
('Y', SumResultY)
) c (sumresult, value)
)
select Foo_FK,
[201312_0_X], [201312_0_Y], [201312_1_X], [201312_1_Y],
[201401_0_X], [201401_0_Y], [201401_1_X], [201401_1_Y]
from cte
pivot
(
max(value)
for col in ([201312_0_X], [201312_0_Y], [201312_1_X], [201312_1_Y],
[201401_0_X], [201401_0_Y], [201401_1_X], [201401_1_Y])
) piv;
See SQL Fiddle with Demo