Aggregate and concatenate from two tables based on comparison between columns - sql

I have two tables like this:
Table1
A T
a1 t1
a2 t2
a3 t3
a4 t4
a5 t5
...
...
Table2
E T
e1 t1
e2 t2
e3 t3
e4 t4
e5 t5
...
...
what I wanted to achieve is this:
Table 3
E A'
e1 a1,a2,a3
e2 a4,a5,a6
...
...
The aggregation A' is done like this: In table 2 for each e there is a value in column T : t and with that t you look for the last 3 values in Table 1 that are less than the t in question. So a1, a2, a3 are values of A whose t values are less than t1 in Table 2 whose E is e1.
I know that I could write two queries for this like this:
ResultSet (rt) -> select t from e
and then iterate ResultSet and do something like this :
select A from Table1 where t < rt[i] limit 3 - not sure how to concatenate here :)
but I m pretty sure this is utterly inefficient. There should be a better way to do this.
I m working with Postgresql.
If it had been a dataframe from a file I would use python's pandas. Also I know that python has read_sql but the tables are very huge I don't want to load the whole table in memory which I think it won't but not sure either - anyway its a separate story.
How do we solve this in SQL? Any ideas please.

In table 2 for each e there is a value in column T : t and with that t you look for the last 3 values in Table 1 that are less than the t in question.
I don't understand the results follow this logic. But based on your description, you can use a lateral join:
select t2.*, t1.the_as
from t2 left join lateral
(select array_agg(t1.a) as the_as
from (select t1.*
from t1
where t1.T <= t2.T
order by t1.T desc
limit 3
) t1
) t1
on 1=1;
Note that this uses arrays rather than strings because I think arrays are a better data structure for storing multiple values. That said, you can just use string_agg() instead, if you really want a string. The syntax would be string_agg(t1.a, ',').

Related

An SQL chalenge

I would like to solve this with pure SQL sentences in an AMDP method, I could solve this easily in ABAP, even in an AMDP method using loops, but as I said, I would like to solve this with SQL sentences, without use any kind of loops.
Please take a look on this image:
I have 2 columns, the first I'll name as D and the second as E
The D column, is a result of a SELECT SUM, but the E column, is a calculated column, and it should work as follow:
First line both columns are equal E1 = D1
In the second line, E2 = E1 + D2
In the third line, E3 = E2 + D3
In the forth line, E4 = E3 + D4
And so on.
So that's it. Is it possible to solve this with pure SQL sentences?
Have the SUM in a subquery, then do a select from that subquery along with a row number. Insert that into a temporary table. Then select from that temporary table and do a join to the same table based on the row number, looking for the previous row.
SELECT D, ROW_NUMBER() AS ROW_NUM
INTO #TempTable
FROM (SELECT SUM() AS D FROM table) a
SELECT
t1.D
,CASE
t2.D IS NULL THEN t1.D
ELSE t2.D + t1.D AS E
FROM #TempTable t1
LEFT JOIN #TempTable t2 ON t1.ROW_NUM = t2.ROW_NUM + 1

combine two oracle sql results into single dataset

I have two selects and I want to combine them in such a way, that only one row that has key column matched in both selects are returned(one row in first select and one row in 2nd select). Is there any built-in way in Oracle 10g to achieve this?
I have two sql as below
Query 1:
select c11, c12 from table t1
where c11=1000
Query 2:
select c21, c22
from t2
where c21=1000
I want to combine both query 1 and query 2 on key columns(OPTYREVN_OPTY_XI, OPTYREVN_SEGMENT_XI and OPTYREVN_OPTYREVNCRM_ID). My output should contain only the only one row which found in results of query 1 and query 2.
I am not sure to use UNION or Intersect or left outer join.
Kindly suggest me some solution which will be helpful in this scenario. Thanks.
So, If I got you right, you want to have c1 , c2 , c33 , c21 , c22 and c 23 on one line, if both queries return only one line and no information can link them, this should work...
SELECT a.* , b.*
FROM (select c1, c2, c33
from t1, t3
where c1= 1000 and c33 is null) a ,
(select c21, c22, c23
from t2
where c21= 1000) b
/*WHERE...*/ --you could always use some condition linking a and b
I think you would want to use a join:
SELECT c1, c2, c33, c21, c22, c23
FROM t1 INNER JOIN t3 ON <key columns>
INNER JOIN t2
ON t1.c1 = t2.c21
WHERE t1.c1 = 1000
AND t3.c33 IS NULL;

Error in query, two select statements with left join?

I have two select statements:
A: select a.1,a.2,a.3 from table1 a
B: select b.1,b.2,b.3 from table1 b
Now I join these two statements?
I tried in the below way and got error:
select *
(select a.1,a.2,a.3 from table1 a) aa
left join
(select b.1,b.2,b.3 from table1 b) bb
aa.a.1 = bb.b.1;
Within your Left Join, you need to include the ON/WHERE clause:
select *
(select a.1,a.2,a.3 from table1 a) aa
left join
(select b.1,b.2,b.3 from table1 b) bb
aa.a.1 = bb.b.1,
should be in the format:
SELECT *
(SELECT a.1, a.2, a.3 FROM table1 a) aa
LEFT JOIN
(SELECT b.1,b.2,b.3 FROM table2 b) bb
ON a.1 = b.1
WHERE ...
For more clarification, please see this image:
As it currently stands, it's quite hard to distinguish what exactly your requirements are in terms of what you want the query to return, but I op this image will visually display the syntax for each of the joins.
Numbers (a.1, a.2, i.e. columns 1 and 2 for table alias a) are usually not valid column names. Are the columns really named thus? Then you'd need something to indicate that these are column names. Depending on the dbms that could be `a.1` or "a.1" or [a.1]. Or use different names, such as num1, num2, num3, or one, two, three, etc.
EDIT: You are also missing the word ON before your criteria. And aa.a.1 is invalid, for your table alias is now aa and the column name is still "1" and the table alias a is no longer known. So it must be a."1" instead. Moreover you are missing the keyword FROM for your first derived table.
select *
from (select a."1", a."2", a."3" from table1 a) aa
left join (select b."1", b."2", b."3" from table1 b) bb ON aa."1" = bb."1";

SQL index relative to another field

I have, as part of a query, a bunch of distinct pairs of values:
a d
a e
a f
b g
b h
c i
I'd like to be able to calculate an counter relative to the first field:
a d 1
a e 2
a f 3
b g 1
b h 2
c i 1
I can't use the position in the temporary table - apart from anything else it goes too high, whereas the value I need can't go over 2 digits (and there isn't going to be more than 50 entries with the same first field. Are there any methods or techniques to help?
Thanks for any help!
select t1.c1 , t1.c2 , count(t2.c1) cnt
from mytable t1
join mytable t2 on t1.c1 = t2.c1 and t1.c2 >= t2.c2
group by t1.c1, t1.c2
order by t1.c1, cnt
Demo
Explanation
This query assumes that the pair (c1,c2) is unique.
To rank each row (c1,c2) the query counts the number of rows within the group c1 where c2 is less than or equal to c2. For example, for (a,e), there are 2 rows within the group a that are less than or equal to e (namely d and e).
You didn't specify your DBMS, so this is ANSI SQL:
select a,
b,
row_number() over (partition by a order by b) as idx
from the_table;
SQLFiddle: http://sqlfiddle.com/#!15/4cf96/1
row_number() is a window function which will generate a unique number based on the "grouping" and ordering defined with the partition by clause. The Postgres manual has a nice introduction to window functions: http://www.postgresql.org/docs/current/static/tutorial-window.html
This is going to be much faster than a self join

SQL - Join two query in same query with two rows

i have one query that i need include the status in another row, i think that it's easy but i'm not remember it..
status
A
B
C
D
job
1
2
3
i want a output like:
job status
1 A
1 B
1 C
1 D
2 A
2 B
2 C
2 D
...
Can anyone help?
that is called CROSS JOIN
SELECT *
FROM status CROSS JOIN job;
I'm just guessing your table layout here because you did not give it in your question.
SELECT t1.job, t2.status
FROM t1 INNER JOIN t2 ON t1.something = t2.something
Note that if you had given the table structure something, t1 and t2 would actually be the real names.
If there is no particular key and you just want to match every value of t1.job to every value of t2.status then this will do the job:
SELECT t1.job, t2.status
FROM t1, t2
You might want to read a little bit about JOINs in SQL, here's a good resource:
http://www.w3schools.com/sql/sql_join.asp
As per your case, you can simply do:
SELECT * FROM job, status
Assuming that those are table names and these are the only columns in there.
EDIT:
Link with explanation on how CROSS JOIN works as well:
http://www.w3resource.com/sql/joins/cross-join.php