Make a select query with stored procedure from multiple independent tables - sql

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

Related

How to Update the Following Table with MERGE in Oracle?

I have the following data set (Oracle 12):
Table X
+---------+--------+---------------+--------+
| COLN | COLM | COLK | COLP |
+---------+--------+---------------+--------+
| 1 | 500 | K1 | 777 |
+---------+--------+---------------+--------+
Table A
+---------+--------+---------------+--------+
| COL1 | COL2 | COL3 | COL4 |
+---------+--------+---------------+--------+
| 1 | K1 | 500 | B |
| 1 | K2 | 500 | NULL |
+---------+--------+---------------+--------+
Table B
+---------+--------+---------+
| COLZ | COLX | COLW |
+---------+--------+---------+
| 1 | K1 | 777 |
| 1 | K2 | 678 |
+---------+--------+---------+
The three tables have the following commonality:
X.COLN = A.COL1 = B.COLZ
X.COLk = A.COL2 = B.COLX
X.COLM = A.COL3
I need to write a query which retrieves values for the following columns in one query:
X.COLK, X.COLP, B.COLX, B.COLW
The ultimate goal is, if the following conditions are met:
If there more than one record in Table A where A.COL1's and A.COL3's are matching (and there is a corresponding record in Table X)
And one of the rows is not null, e.g. A.COL4 = B, and another one is NULL
I update Table X to replace X.COLK, X.COLP (K1 and 777) in my MERGE statement with values in Table B (B.COLX, B.COLW -- K2 and 678).
Is this possible?
MERGE INTO X FX
USING (
SELECT COLX ONGOING_X, COLW ONGOING_W
FROM B
WHERE (COLZ, COLX) IN
(SELECT COL1, COL2
FROM A
WHERE COL3 = ?
AND COL1 = ?
AND COL4 IS NULL)
) NEW_B
ON (FX.COLk = ?
AND FX.COLP = ?)
WHEN MATCHED THEN
UPDATE SET
FX.COLk = NEW_B.ONGOING_X,
FX.FOLP = NEW_B.ONGOING_W;
You may do a MERGE using ROWID.
MERGE INTO x tgt USING (
WITH c AS (
SELECT col1,
col3,
MAX(
CASE
WHEN col4 IS NULL THEN col2
END
) AS col2 --Ongoing col2 as indicated from col4
FROM a
GROUP BY col1,
col3
HAVING COUNT(
CASE
WHEN col4 IS NULL THEN 1
END
) = 1 AND COUNT(col4) = 1 --Contains one and exactly one NULL and one NON NULL
) SELECT x.rowid AS rid,
b.*
FROM x
JOIN c ON c.col1 = x.coln AND c.col3 = x.colm
JOIN b ON b.colz = c.col1 AND b.colx = c.col2 --Join with ongoing value from c( a.k.a table A )
)
src ON ( tgt.rowid = src.rid ) --ROWID match
WHEN MATCHED THEN UPDATE SET tgt.colk = src.colx,
tgt.colp = src.colw;
Demo

I am having hard time writing a HiveQL Join

I am pretty sure this question have been asked but can't get my search query to return the answer. I have two table
**Table Online**
Col1 Col2 Score |
a b 1 |
a c 2 |
a d 3 |
f e 4 |
**Table Offline**
Col1 Col2 Score |
a m 10 |
a c 20 |
a d 30 |
t k 40 |
**Table Output**
Col1 Col2 Online.Score Offline.Score |
a c 2 20 |
a d 3 30 |
a b 1 |
a m 10 |
You can do this with a full join:
select coalesce(onl.col1, ofl.col1) as col1,
coalesce(onl.col2, ofl.col2) as col2,
onl.score, ofl.score
from (select onl.*
from online onl
where onl.col1 = 'a'
) onl full join
(select ofl.*
from offline ofl
where ofl.col1 = 'a'
) ofl
on onl.col1 = ofl.col1 and onl.col2 = ofl.col2;
Filtering is tricky withe full join, which is why this uses a subquery.
Use below query!
SELECT online.col1
,online.col2
,coalesce(online.score, 0) AS onlinescore
,coalesce(offlilne.score, 0) AS offlinescore
FROM online
INNER JOIN offline
ON online.col1 = offline.col1
AND online.col2 = offline.col2
UNION ALL
SELECT online.col1
,online.col2
,coalesce(online.score, 0) AS onlinescore
,'' AS offlinescore
FROM online
LEFT JOIN offline
ON online.col1 = offline.col1
AND online.col2 = offline.col2
WHERE offline.col1 IS NULL
UNION ALL
SELECT offline.col1
,offline.col2
,'' AS onlinescore
,coalesce(offline.score, 0) AS offlinescore
FROM offline
LEFT JOIN online
ON online.col1 = offline.col1
AND online.col2 = offline.col2
WHERE online.col1 IS NULL

SQL help on count in certain ID

Do you know how to display only the lines in table for same ID where col3 is not 'X'?
e.g., in the following table, it should display only ID 2 (as all the col2 are null)
ID | col1 | col2 | col3
---+------+------+-----
1 | 0 | 0 | X
1 | D | C | null
1 | D | C | null
2 | 0 | 0 | null
2 | D | C | null
2 | D | C | null
It should work for all ID with some many line by ID and only the same ID with all line having null.
If you are looking to get records where ID does not have at least one X in col 3 for other records:
SELECT Y.*
FROM Your_Table Y
WHERE Y.ID NOT IN (SELECT X.ID FROM YOUR_TABLE X WHERE X.ID=Y.ID AND X.COL3='X')
Most DBMS support 3 valued logic - True, False, and Undefined. NULL <> 3 is undefined, since NULL is an unknown value. You need to handle NULLs explicitly.
SELECT *
FROM Your_Table
WHERE col3 <> X
OR col3 IS NULL;
select * from table
where (col1 = col2) and (col3 <> 'X')
Use window functions or not exists:
select t.*
from t
where not exists (select 1 from t t2 where t2.id = t.id and t2.col3 = 'X');

Want to know all possible Parent and Child Rows against specific Id?

How to know all possible Parent and Child Rows against specific Id?
e.g. have following table:
MyTable:
-----------------------------------------------------
| Id | PId | Description |
-----------------------------------------------------
| 1 | NULL | A is Parent |
| 2 | 1 | B is Child of A |
| 3 | 2 | C is Child of B |
| 4 | NULL | D is Parent |
| 5 | NULL | E is Parent |
| 6 | 5 | F is Child of E |
-----------------------------------------------------
want to know all possible parent and child when pass spesific id
e.g.
CASE-01:
When #MyLookupId=2 OR #MyLookupId=1 OR #MyLookupId=3 One of from them Then Result Should Be,
-------
| Id |
-------
| 1 |
| 2 |
| 3 |
-------
CASE-02:
When #MyLookupId=4 Then Result Should Be,
-------
| Id |
-------
| 4 |
-------
CASE-03:
When #MyLookupId=6 Then Result Should Be,
-------
| Id |
-------
| 5 |
| 6 |
-------
Here is SQL for table:
IF OBJECT_ID('tempdb.dbo.#MyTable', 'U') IS NOT NULL DROP TABLE #MyTable;
SELECT * INTO #MyTable FROM (
SELECT (1)Id, (NULL)PId, ('A IS Parent')Description UNION ALL
SELECT (2)Id, (1)PId, ('B IS Child of A')Description UNION ALL
SELECT (3)Id, (2)PId, ('C IS Child of B')Description UNION ALL
SELECT (4)Id, (NULL)PId, ('D IS Parent')Description UNION ALL
SELECT (5)Id, (NULL)PId, ('E IS Parent')Description UNION ALL
SELECT (6)Id, (5)PId, ('F IS Child of E')Description ) AS tmp
SELECT * FROM #MyTable
You could use recursive cte
-- temp returns full tree of each rootId (parentid = null)
;WITH temp AS
(
SELECT sd.Id, sd.PId, sd.Id AS RootId
FROM #MyTable sd
WHERE sd.PId IS NULL
UNION ALL
SELECT sd.Id, sd.PId, t.RootId
FROM temp t
INNER JOIN #MyTable sd ON t.Id = sd.PId
)
SELECT t2.Id
FROM temp t
INNER JOIN temp t2 ON t2.RootId = t.RootId
WHERE t.Id = #Id
OPTION (MAXRECURSION 0)
Demo link: http://rextester.com/RAITMT72805
The answer given by TriV works, but requires a calculation of the entire hierarchy of your source table each time the query is run, which may not perform well at larger scale.
A more narrow approach is to find the Parent and Child records that only relate to the ID you are searching for:
declare #t table(ID int, PID int);
insert into #t values(1,null),(2,1),(3,2),(4,null),(5,null),(6,5);
declare #ID int = 2;
with c as
(
select ID
,PID
from #t
where ID = #ID
union all
select t.ID
,t.PID
from #t t
join c
on(t.PID = c.ID)
)
,p as
(
select ID
,PID
from #t
where ID = #ID
union all
select t.ID
,t.PID
from #t t
join p
on(t.ID = p.PID)
)
select ID
from p
union all
select ID
from c
where c.ID <> #ID
order by ID;
Output:
ID
````
1
2
3

sql row value depending on other row value

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