An SQL chalenge - hana-sql-script

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

Related

Select entries that have non repeating values on a specific column (although other columns may have repeating or non repeating values) (SQL)

Let's say I have the following table:
A
B
C
D
a1
b1
c1
d1
a1
b1
c1
d2
a2
b2
c3
d3
a2
b2
c4
d3
I want to filter and see all four columns for entries that have the same value con column A but different on column C, so I get only this as a result:
A
B
C
D
a2
b2
c3
d3
a2
b2
c4
d3
I don't really care if values con columns B and D are the same or different, although I would like to have them in my table to do further analysis later.
Using the DISTINCT statement would give me all the columns as a result, as they all are different in some column, so that doesn't work for me.
I read some questions (like this one) and the answers recommended using the row_number() over(partition by...) clause, although the use they gave it doesn't quite fit my problem (I think), as it would also return the first row with a repeating value on column C.
Any ideas how this could be done?
You can use exists:
select t.*
from t
where exists (select 1
from t t2
where t2.a = t.a and t2.c <> t.c
)
order by t.a;
You could use a self join
select t1.*
from t t1
join t t2 on t1.a=t2.a and t1.c<>t2.c

Aggregate and concatenate from two tables based on comparison between columns

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, ',').

How should I order a subset of a query returned and place it on the top of the result?

I have a query for example:
select name from tableA;
which gives the following:
a
b
c
d1
d2
d3
e1
e3
I would like to have it ordered with the "d's" on top of the list.
e.g.
d1
d2
d3
a
b
c
e1
e2
e3
I tried to do a union with two queries but it seems to not be working. I believe I'm missing something but can't figure it out.
I got this far:
select name from tableA where name like 'd%';
union
select name from tableA;
You can try using a CASE statement in the ORDER BY clause:
SQL Fiddle
SELECT name
FROM TableA
ORDER BY
CASE WHEN name LIKE 'd%' THEN 0 ELSE 1 END,
name

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

Is possible have different conditions for each row in a query?

How I can select a set of rows where each row match a different condition?
Example:
Supposing I have a table with a column called name, I want the result ONLY IF the first row name matches 'A', the second row name matches 'B' and the third row name matches 'C'.
Edit:
I want to do this to work without a fixed size, but in a way I can define the sequence like R,X,V,P,T and it matches the sequence, each one in a row, but in the order.
you can, but probably not in a way you would want:
if your table has a numeric id field, that is incremented with each row, you can self join that table 3 times (lets say as "a", "b" and "c") and use the join condition a.id + 1 = b.id and b.id + 1 = c.id and put you filter in a where clause like: a.name = 'A' AND b.name = 'B' AND c.name = 'C'
but don't expect performance ...
Assuming that You know how to provide a row number to your rows (ROW_NUMBER() in SQL Server, for instance), You can create a lookup (match) table and join on it. See below for explanation:
LookupTable:
RowNum Value
1 A
2 B
3 C
Your SourceTable source table (assuming You already added RowNum to it-in case You didn't, just introduce subquery for it (or CTE for SQL Server 2005 or newer):
RowNum Name
-----------
1 A
2 B
3 C
4 D
Now You need to inner join LookupTable with your SourceTable on LookupTable.RowNum = SourceTable.RowNum AND LookupTable.Name = SourceTable.Name. Then do a left join of this result with LookupTable on RowNum only. If there is LookupTable.RowNum IS NULL in final result then You know that there is no complete match on at least one row.
Here is code for joins:
SELECT T.*, LT2.RowNum AS Matched
FROM LookupTable LT2
LEFT JOIN
(
SELECT ST.*
FROM SourceTable ST
INNER JOIN LookupTable LT ON LT.RowNum = ST.RowNum AND LT.Name = ST.Name
) T
ON LT2.RowNum = T.RowNum
Result set of above query will contain rows with Matched IS NULL if row is not matching condition from LookupTable table.
I suppose you could do a sub query for each row, but it wouldn't perform well or scale well at all and would be hard to maintain.
This may be close to what your after... but I need to know where you're getting your values for A, B, C etc...
Select [insert your fields here]
FROM
(Select T1.Name, T1.Age, RowNum as t1RowNum from T T1 order by name) T1O
Full Outer JOIN
(Select T2.Name, T2.Age, RowNum as T2rowNum From T T2 order By name) T2O
ON T1O.T1RowNum+1 = T2O.T2RowNum