sql row value depending on other row value - sql

My table looks like this:
Name | Text | GroupID
------------------------------------
A | sometext | 1
B | x | 2
C | x | 3
D | sometext2 | 1
E | x | 2
F | abc |
G | sometext3 | 1
H | x | 2
I | x | 3
GroupID 1 -> It's a header line and should not be selected
GroupID 2-... -> IT's a Subline from the above header (ID = 1) and should be selected with the text of its header line!
If there is no group id at all then the line should be selected with no text
So when selecting everything from the above table the result should be:
B sometext 2
C sometext 3
E sometext2 2
F
H sometext3 2
I sometext3 3
Does anyone have an idea how to build the select-stmt?

try this query:
select
t1.name,
case when t1.groupid is null then '' else
(select q.text from
(select rownum as counter,name,text from TableName where groupid=1)q
where
q.counter = (select max(rownum) from TableName t2 where groupid=1 and
t2.name<=t1.name))end as Text,
t1.groupid
from
TableName t1
where
(t1.groupid<>1 or t1.groupid is null);

try also this (live demo in SQLFiddle):
-- here I return the headers without subheaders - GroupId NULL
select name,
case
when GroupID is null then null
else text
end header
from t
where groupid is null
union all
-- here I return the the others
select sub.name,
head.text
from t head
inner join (
-- here I take for each sub the associated header
select t.name, max(h.name) header
from t
inner join (select t.Name, t.Text from t where groupid = 1) h
on h.name < t.name
where groupid > 1
group by t.name
) sub on head.name = sub.header
order by 1

Related

Make a select query with stored procedure from multiple independent tables

Table A
id | food_id | price
1 | 3 | 5
2 | 7 | 9
3 | 3 | 8
Table B
id | drink_id | price | type_id
1 | 8 | 8 | 3
2 | 6 | 9 | 3
3 | 6 | 10 | 1
Table C
id(food_id) | Name
3 | Banana
7 | Strawberry
I have 3 tables like this. I want the result of the query written with the stored procedure to be as follows.
column 1
13 (select sum(price) from tableA where food_id = 3)
column 2
2 (Select count(*) from tableB where drink_id = 6)
column 3
9 (Select sum(price) from tableB where drink_id = 6 and type_id = 3)
column 4
Banana (Select Name from tableA a left join tableC c On a.id = c.id) where a.id = 1)
Suppose there are millions of rows of data in these tables. How to write the best stored procedure?
NOTE: Not validated as I don't have your tables, but this format should work once you put it into an SP.
-- put this into an SP
-- delcare varaibles, probably should change them to match results (could be decimal or int depending on what your SUM does)
DECLARE #SumPriceFood AS VARCHAR(50)
DECLARE #CountDrink AS VARCHAR(50)
DECLARE #SumPriceDrink AS VARCHAR(50)
DECLARE #Name AS VARCHAR(50)
-- get your data (not tested these as they are your tables)
SELECT #SumPriceFood = SUM(price) from tableA where food_id = 3
SELECT #CountDrink = COUNT(*) from tableB where drink_id = 6
SELECT #SumPriceDrink = sum(price) from tableB where drink_id = 6 and type_id = 3
SELECT #Name = Name from tableA a left join tableC c On a.id = c.id where a.id = 1
-- now just select the variable values you populated above for your results
SELECT #SumPriceDrink AS SumPriceDrink, #CountDrink AS CountDrink, #SumPriceDrink AS SumPriceDrink, #Name AS Name
you can use your queries as subqueries.
For an Stored procedure it isn't enough but who knows what ypu need it for
DECLARE #food_id INTEGER = 3;
DECLARE #drink_id int = 6;
DECLARE #type_id INTEGER = 3;
DEClARE #a_id int = 1;
SELECT
(select sum(price)from tableA where food_id=#food_id) col1,
(Select count(*) from tableB where drink_id=#drink_id) col2,
(Select sum(price) from tableB where drink_id=#drink_id and type_id=3) col3,
(Select Name from tableA a left join tableC c On a.id = c.id where a.id = #a_id) col4
col1 | col2 | col3 | col4
---: | ---: | ---: | :-----
13 | 2 | 9 | Banana
CREATE PROCEDURE Getdata
#food_id AS INTEGER,#drink_id int,#type_id INTEGER ,#a_id int
AS
SELECT
(select sum(price)from tableA where food_id=#food_id) col1,
(Select count(*) from tableB where drink_id=#drink_id) col2,
(Select sum(price) from tableB where drink_id=#drink_id and type_id=3) col3,
(Select Name from tableA a left join tableC c On a.id = c.id where a.id = #a_id) col4
EXEC Getdata #food_id = 3,#drink_id = 6,#type_id = 3,#a_id = 1;
col1 | col2 | col3 | col4
---: | ---: | ---: | :-----
13 | 2 | 9 | Banana
db<>fiddle here

I want to remove some customers associated with one brand from other brand in same column in PostgreSQL

I need customers which are present in the x and y brand should be removed from a brand in the final output
Customer_id |brand
1 | a
2 | a
3 | a
4 | a
1 | x
3 | y
5 | z
Final Output should be like this -
Customer_id |brand
2 | a
4 | a
1 | x
3 | y
5 | z
You could use exists:
select t.*
from mytable t
where brand <> 'a' or not exists (
select 1 from mytable t1 where t1.customerid = t.customerid and t1.brand <> 'a'
)
Altenatively, you can use window functions:
select
from (
select t.*, bool_and(brand = 'a') over(partition by customerid) has_only_a
from mytable t
) t
where brand <> 'a' or has_only_a

Find all records that share specific comment

I have an existing table1:
User Comment Group
---------------------
1 foo a
2 bar a
3 baz b
4 123 a
5 bar c
6 foo d
7 654 a
Assume that I need to select all Users with Comment foo
select * from [table1] t1 where t1.[Comment] = 'foo';
User Comment Group
---------------------
1 foo a
6 foo d
Now I want to find all the users in the same Groups:
User Comment Group
---------------------
1 foo a
2 bar a
4 123 a
6 foo d
How can I do this? I thought like this:
select t1.*
from [table1] t1
left join [table1] t2 on t1.[User] = t2.[User]
and t1.[Comment] = 'foo'
But this is returning all records in [table1]. What am I doing wrong?
You could use exists:
select t.*
from mytable t
where exists (
select 1 from mytable t1 where t1.comment = 'foo' and t1.group = t.group
)
For performance with this query, you want an index on (comment, group).
With the operator IN:
select * from tablename
where [Group] in (
select [Group] from tablename
where [Comment] = 'foo'
)
See the demo.
Results:
> User | Comment | Group
> ---: | :------ | :----
> 1 | foo | a
> 2 | bar | a
> 4 | 123 | a
> 6 | foo | d
> 7 | 654 | a

T-sql using values from one table and displaying them in different columns

My database Table looks like:
ID | INDEX | Value |
1 | 0 | 3 |
1 | 1 | 5 |
1 | 2 | 7 |
2 | 0 | 4 |
2 | 1 | 6 |
2 | 2 | 2 |
What I want my output to look like is the difference of the values column based on their index
i.e. value(id=2,index = i) - value(id = 1, index = i) so the output table will look like
INDEX | Delta Value |
0 | 1 |
1 | 1 |
2 | -5 |
My attempt at solving this problem is as follows:
SELECT Top 6
col1.value column1,
col2.value column2,
col2.value - col1.value
FROM My_Table col1
INNER JOIN My_Table col2
ON col1.index = col2.index
WHERE col1.id = 1
OR col2.id = 2
I know there are problems with this query. But I just haven't been able to produce the output that I want. Any help is appreciated.
You can do this by join
select
t1.ind, t1.value - t2.value as delta
from My_Table as t1
inner join My_Table as t2 on t2.id = 2 and t2.ind = t1.ind
where t1.id = 1
Or by simple aggregate:
select
ind, sum(case id when 1 then 1 when 2 then -1 end * value) as delta
from My_Table
group by ind
Do you want something like this?
select
col1.value column1,
col2.value column2,
col2.value - col1.value AS delta
From My_Table col1
INNER JOIN My_Table col2
ON col1.index = col2.index
AND col2.id = 2
where col1.id = 1
have a look at mine
select t1.[index],
t2.value-t1.value
from my_table t1 inner join my_table t2
on t1.[index] = t2.[index]
where t1.id = 1 and t2.id = 2
order by t1.[index]

how to query range?

Raw Data
| ID | STATUS |
| 1 | A |
| 2 | A |
| 3 | B |
| 4 | B |
| 5 | B |
| 6 | A |
| 7 | A |
| 8 | A |
| 9 | C |
Result
| START | END |
| 1 | 2 |
| 6 | 8 |
Range of STATUS A
How to query ?
This should give you the correct ranges:
SELECT
STATUS,
MIN(ID),
max_id
FROM (
SELECT
t1.STATUS,
t1.ID,
COALESCE(MAX(t2.ID), t1.ID) max_id
FROM
yourtable t1 LEFT JOIN yourtable t2
ON t1.STATUS=t2.STATUS AND t1.ID<t2.ID
WHERE
NOT EXISTS (SELECT NULL
FROM yourtable t3
WHERE
t3.STATUS!=t1.STATUS
AND t3.ID>t1.ID AND t3.ID<t2.ID)
GROUP BY
t1.ID,
t1.STATUS
) s
WHERE
status = 'A'
GROUP BY
STATUS,
max_id
Please see fiddle here.
You are probably better off with a cursor-based solution or a client-side function.
However, if you were using Oracle - the following would work.
WITH LOWER_VALS AS
( -- All the Ids with no immediate predecessor
SELECT ROWNUM AS RN, STATUS, ID AS LOWER FROM
(
SELECT STATUS, ID
FROM RAWDATA RD1
WHERE RD1.ID -1 NOT IN
(SELECT ID FROM RAWDATA PRED_TABLE WHERE PRED_TABLE.STATUS = RD1.STATUS)
ORDER BY STATUS, ID
)
) ,
UPPER_VALS AS
( -- All the Ids with no immediate successor
SELECT ROWNUM AS RN, STATUS, ID AS UPPER FROM
(
SELECT STATUS, ID
FROM RAWDATA RD2
WHERE RD2.ID +1 NOT IN
(SELECT ID FROM RAWDATA SUCC_TABLE WHERE SUCC_TABLE.STATUS = RD2.STATUS)
ORDER BY STATUS, ID
)
)
SELECT
L.STATUS, L.LOWER, U.UPPER
FROM
LOWER_VALS L
JOIN UPPER_VALS U ON
U.RN = L.RN;
Results in the set
A 1 2
A 6 8
B 3 5
C 9 9
http://sqlfiddle.com/#!4/10184/2
There is not a lot to go on from what you put, but I think this might work. I am using T-SQL because I don't know what you are using?
SELECT
min(ID)
, max(ID)
FROM RawData
WHERE [Status] = 'A'