Without association select all records from two differnet tables - sql

Without association I want to fetch records from two different table.
Note:
In name column, to identify I want to add table name. (i.e: t1 test1)
There is no relationship between two tables
TABLE A
uid name email
1 test1 a#a.com
2 test2 b#a.com
3 test3 c#a.com
4 test4 d#a.com
TABLE B
pid name email
1 test1 123#a.com
2 test2 456#a.com
3 test3 789#a.com
4 test4 900#a.com
RESULT
uid pid name email
1 null t1-test1 a#a.com
2 null t1-test2 b#a.com
3 null t1-test3 c#a.com
4 null t1-test4 d#a.com
null 1 t2-test1 123#a.com
null 2 t2-test2 456#a.com
null 3 t2-test3 789#a.com
null 4 t2-test4 900#a.com
My try so far:
SELECT distinct table1.id, table1.name, table.email, table2.id, table1.name, table.email
FROM table1, table2
Above query giving repeated records

I think a SQL UNION and the CONCAT() function should help you out here.
SELECT table1.id, CONCAT('t1-',table1.name) as name, table1.email
FROM table1
UNION ALL
SELECT table2.id, CONCAT('t2-',table2.name) as name, table2.email
FROM table1
ORDER BY name

WITH cte AS (
(
SELECT
row_number() OVER (),
NULL,
't1-' || a.name AS name,
a.email
FROM
a)
UNION ALL
SELECT
NULL,
row_number() OVER (),
't2-' || b.name,
b.email
FROM b
)
SELECT
*
FROM
cte
ORDER BY
name;

Related

Query to display one to many result in a single table

Ive been trying to use the GROUP function and also PIVOT but I cannot wrap my head around how to merge these tables and combine duplicate rows. Currently my SELECT statement returns results with duplicate UserID rows but I want to consolidate them into columns.
How would I join TABLE1 and TABLE2 into a new table which would look something like this:
NEW TABLE:
UserID Username ParentID 1 ParentID 2
--------- -------- -------- ----------
1 Dave 1 2
2 Sally 3 4
TABLE1:
UserID Username ParentID
--------- -------- --------
1 Dave 1
1 Dave 2
2 Sally 3
2 Sally 4
Table 2:
ParentID Username
--------- --------
1 Sarah
2 Joe
3 Tom
4 Mark
O r a c l e
The with clause is here just to generate some sample data and, as such, it is not a part of the answer.
After joining the tables you can use LAST_VALUE analytic function with windowing clause to get the next PARENT_ID of the user. That column (PARENT_ID_2) contains a value only within the first row of a particular USER_ID (ROW_NUMBER analytic function). Afterwords just filter out rows where PARENT_ID_2 is empty...
Sample data:
WITH
tbl_1 AS
(
Select 1 "USER_ID", 'Dave' "USER_NAME", 1 "PARENT_ID" From Dual Union All
Select 1 "USER_ID", 'Dave' "USER_NAME", 2 "PARENT_ID" From Dual Union All
Select 2 "USER_ID", 'Sally' "USER_NAME", 3 "PARENT_ID" From Dual Union All
Select 2 "USER_ID", 'Sally' "USER_NAME", 4 "PARENT_ID" From Dual
),
tbl_2 AS
(
Select 1 "PARENT_ID", 'Sarah' "USER_NAME" From Dual Union All
Select 2 "PARENT_ID", 'Joe' "USER_NAME" From Dual Union All
Select 3 "PARENT_ID", 'Tom' "USER_NAME" From Dual Union All
Select 4 "PARENT_ID", 'Mark' "USER_NAME" From Dual
)
Main SQL:
SELECT
*
FROM (
SELECT
t1.USER_ID "USER_ID",
t1.USER_NAME "USER_NAME",
t1.PARENT_ID "PARENT_ID_1",
CASE
WHEN ROW_NUMBER() OVER(PARTITION BY t1.USER_ID ORDER BY t1.USER_ID) = 1
THEN LAST_VALUE(t1.PARENT_ID) OVER(PARTITION BY t1.USER_ID ORDER BY t1.USER_ID ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING)
END "PARENT_ID_2"
FROM
tbl_1 t1
INNER JOIN
tbl_2 t2 ON(t1.PARENT_ID = t2.PARENT_ID)
)
WHERE PARENT_ID_2 Is Not Null
... and the Result ...
-- USER_ID USER_NAME PARENT_ID_1 PARENT_ID_2
-- ---------- --------- ----------- -----------
-- 1 Dave 1 2
-- 2 Sally 3 4
The windowing clause in this answer
ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING
takes curent and next row and returns the value defined by the analytic function (LAST_VALUE) taking care of grouping (PARTITION BY) and ordering of the rows. Regards...
This is mySql ver 5.6. Create a concatenated ParentID using group concat then separate the concatenated ParentID (1,2) and (3,4) into ParentID 1 and Parent ID 2.
SELECT t1.UserID,
t1.Username,
SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(t1.ParentID), ',', 1), ',', -1) AS `ParentID 1`,
SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(t1.ParentID), ',', 2), ',', -1) as `ParentID 2`
FROM TABLE1 t1
INNER JOIN TABLE2 t2 on t1.ParentID = t2.ParentID
GROUP BY t1.UserID
ORDER BY t1.UserID;
Result:
UserID Username ParentID 1 ParentID 2
1 Dave 1 2
2 Sally 3 4

SQL query based on another table

I have tables like this:
table 1:
FNAME
ID1
FID
BREAD
XYZ
18BREAD
FISH
ABC
45FISH
BREAD_OLD
BNQ
18BREAD_OLD
BACON
TBG
77BACON
EGGS
CGS
99EGGS
BANANA
BHG
BANANA18
table 2:
FNAME
FID
BREAD
18
FISH
45
BACON
77
EGGS
99
currently a simple search is done on table 1 to find id's of food as follows:
SELECT ID1
FROM TABLE1
WHERE NAME IN NAME_LIST
so for example when the name list is: ('BREAD','FISH') then it returns XYZ, ABC. The problem is this misses 'BREAD_OLD' which is an older version with the same ID. (18)
I need to change this so now the search is done based on the FID of food rather than the NAME to find affected foods but I cannot change the input.
eg: given a list of foods: ('BREAD', 'FISH')
the result should be XYZ, ABC, BNQ (because BREAD matches 18 which matches BNQ in table 1)
how can this can be done? I think I need to use a join or do a 'select within a select' but I'm not sure how this would work with multiple inputs.
edit: ORACLE is the database
edit 2: adding BANANA18 to table 1, needs to be leading match
The correct solution would be to link on the FID fields. However, the FID field on table1 seems to concatenate the ID with the name. The solution would therfore be to extract the numeric value from that field and then use that to link it to the FID field on table 2. For example:
SELECT t1.FNAME, t1.ID1
FROM table1 t1
INNER JOIN table2 t2 ON t2.FID = regexp_replace(t1.FID, '^[^0-9]', '')
WHERE
t2.FNAME IN ('BREAD','FISH');
Assuming that table1.FID equals table2.FID concatenated with table1.FNAME then you do not need (slow) regular expressions and can use a simple equality combined with string concatenation:
SELECT t1.FNAME,
t1.ID1
FROM table1 t1
INNER JOIN table2 t2
ON t1.FID = t2.fid || t1.fname
WHERE t2.FNAME IN ('BREAD','FISH');
Which, for the sample data:
CREATE TABLE table1 (FNAME, ID1, FID) AS
SELECT 'BREAD', 'XYZ', '18BREAD' FROM DUAL UNION ALL
SELECT 'FISH', 'ABC', '45FISH' FROM DUAL UNION ALL
SELECT 'BREAD_OLD', 'BNQ', '18BREAD_OLD' FROM DUAL UNION ALL
SELECT 'BACON', 'TBG', '77BACON' FROM DUAL UNION ALL
SELECT 'EGGS', 'CGS', '99EGGS' FROM DUAL UNION ALL
SELECT 'BANANA', 'BHG', 'BANANA18' FROM DUAL UNION ALL
SELECT 'TOAST', 'TST', 'TOAST181' FROM DUAL;
CREATE TABLE table2 (FNAME, FID) AS
SELECT 'TOAST', 181 FROM DUAL UNION ALL
SELECT 'BREAD', 18 FROM DUAL UNION ALL
SELECT 'FISH', 45 FROM DUAL UNION ALL
SELECT 'BACON', 77 FROM DUAL UNION ALL
SELECT 'EGGS', 99 FROM DUAL;
Outputs:
FNAME
ID1
BREAD
XYZ
BREAD_OLD
BNQ
FISH
ABC
db<>fiddle here
Sample data:
SELECT * FROM TABLE1;
FNAME ID1 FID
-------------------------
BREAD XYZ 18BREAD
FISH ABC 45FISH
BACON TBG 77BACON
EGGS CGS 99EGGS
BREAD_OLD BNQ 18BREAD_OLD
SELECT * FROM TABLE2;
FNAME FID
----------
BREAD 18
FISH 45
BACON 77
EGGS 99
Query:
In query we join TABLE1 and TABLE2 on FID (using REGEX_SUBSTR to extract first n numbers of TABLE1 FID) so row 'BREAD_OLD' will be joined with row 'BREAD' from TABLE2 and when we add condition FNAME IN ('BREAD') both ID1 of 'BREAD' AND 'BREAD_OLD' will be selected.
SELECT ID1
FROM
(SELECT
TO_NUMBER(REGEXP_SUBSTR(FID,'^[0-9]{1,}'),'9999') AS FID,FNAME,ID1
FROM TABLE1)V
JOIN TABLE2 T
ON (V.FID=T.FID)
WHERE T.FNAME IN ('BREAD','FISH')
Result:
ID1
---
XYZ
ABC
BNQ
One option is joining the tables by matching concatenated columns of table2 with the extracted substrings upto _ character for fid column of table1 such as
SELECT id1
FROM table1 t1
JOIN table2 t2
ON REGEXP_SUBSTR(t1.fid,'[^_]+') = t2.fid||t2.fname
WHERE t2.fname IN ('BREAD','FISH')
Demo

Count on UNION in Oracle

I have 3 table and I need to get the details from 2 tables where the count of UNION is greater than 1.But need to apply certain conditions as well
Table A
id entity_id name category
1 45 abcd win_1
2 46 efgh win_2
3 47 efgh1 win_2
4 48 dfgh win_5
5 49 adfgh win_4
Table B
id product_id name parent_id
1 P123 asdf win_1
2 P234 adfgh win_4
Table 3 category_list
id cat_id name
1 win_1 Households
2 win_2 Outdoors
3 win_3 Mixed
4 win_4 Omni
Now I need to have the count of UNION from Table A and Table B where they have count of cat_id greater than 1 and Table A.name != Table B.name
The result which I require is
p_id name cat_id
45 abcd win_1
P123 asdf win_1
46 efgh win_2
47 efgh1 win_2
win_5 is excluded as the count is one and win_4 should be excluded as name in Table A nd B is same.
I have run out of Ideas as i am relatively new to Oracle and DB.Any help is appreciated.
I think you can use exists to ensure that the cat_id is present in both tables
select entity_id as p_id, name, category as cat_id
from table_a a
where exists (select null from table_b where a.category = table_b.parent_id)
union
select entity_id, name, parent_id
from table_b b
where exists (select null from table_a where b.parent_id = table_a.category)
I believe you are looking for something like this -
Select T2.*
from
(Select category
from
(Select name, category from TableA
Union all
Select name, parent_id as category from TableB) t
group by category
having count(distinct name) > 1) T1
Join
(Select entity_id as Pid, name, category from TableA
Union
Select product_id as Pid, name, parent_id as category from TableB) T2
ON T1.category = T2.category;
Would you try this code.
First CTE (Common Table Expression) "list_union" gets the records for each table those have different names then makes the union. with the second CTE "list_cnt" counts the categories and finally gets the result cnt>1 with the last select statement as you pictured.
With
list_union AS (
SELECT
id,
----------
TO_CHAR(entity_id) entity_id,
----------
name,
category
FROM table_A a
WHERE NOT EXISTS(SELECT 1 FROM table_B b WHERE a.name=b.name)
----------
UNION ALL
----------
SELECT
id,
product_id,
name,
parent_id
FROM table_B b
WHERE NOT EXISTS(SELECT 1 FROM table_A a WHERE a.name=b.name)
)
,list_cnt AS (
SELECT
l.*,
----------
COUNT(*) over (PARTITION BY category) cnt
----------
FROM list_union l
)
SELECT
entity_id AS p_id,
name,
category AS cat_id
FROM list_cnt
WHERE cnt>1
ORDER BY cat_id ASC, p_id ASC
;
Just use a union all and window functions:
select ab.*
from (select ab.*,
count(distinct name) over (partition by category) as cnt
from ((select a.* from a
) union all
(select b.* from b
)
) ab
) ab
where cnt > 1;
Although you describe the problem as:
Now I need to have the count of UNION from Table A and Table B where they have count of cat_id greater than 1 and Table A.name != Table B.name
You seem to just want cat_ids that have different names across the two tables. Your sample data includes cat_id = 'win_2', which is not even in the second table.

Delete Rows based on two columns

How can I delete rows based on just two column conditions.
Example
Table 1
id name phone
1 aa 123
1 aa 345
1 bb 123
2 aa 456
1 NULL 123
1 123
My Expected output
id name phone
1 bb 123
2 aa 456
My condition to delete: if id and name is same, delete the rows
If one of the value in a condition is null or blank it should also delete the row as given in the input.
Delete from table1 t where exists (
Select * from
(Select id, name from table1 group by id, name having count(*) > 1) t2 where t.id = t2.id and t.name = t2.name)
This should do what you want. You can do the select first for testing purposes, then remove the Select and uncomment out the delete.
-- This joins on the table the set of data that has more then 1 row with duplicate IDs, and names. Then you can delete from here.
--DELETE t1
SELECT *
FROM Table1 T1
INNER JOIN (
-- this gets all the records that have more then 1 ID and Name that are the same.
SELECT ID, name
FROM Table1
GROUP BY ID, name
HAVING COUNT(*) > 1
) ToDelete ON T1.ID = ToDelete.ID
AND T1.name = ToDelete.name
create table #tablea (
id int,
name varchar(3),
phone int
)
insert into #tablea (id, name, phone)
values
(1,'aa','123'),
(1,'aa','345'),
(1,'bb','123'),
(2,'aa','456')
select * from #tablea
delete a
from #tablea a
inner join (
select id, name
from #tablea
group by id, name
having COUNT(*) > 1
) b on a.id = b.id and a.name = b.name
select * from #tablea
drop table #tablea

t-sql query to get all the rows from Table_A which have at least one matching relatedid in Table_B

Based on the below tables
Table_A
Id RelatedId
---------------
1 1
1 2
1 3
2 4
2 5
2 2
3 7
3 8
4 9
Table_B
RelatedId Name
--------------
2 A
3 B
I want to get all the rows from Table_A which have at least one matching relatedid in Table_B. The Ids from Table_A that do not have match in Table_B will have single row in the result table.
So output (result table) in this case will be
Id RelatedId
---------------
1 1
1 2
1 3
2 4
2 5
2 2
3 Null
4 Null
EDIT: Seems like the question text is confusing for many. So a detailed explanation:
Table_A Id 1 has both 2 and 3 (Related Ids) matching in table_B. So output will have all the rows for 1 from Table_A. Similary Id 2 from Table_A has 2 (Related Id) matching in table_B. So all rows corresponding to 2 from Table_A will be picked up. Since 3 does not have any matching relatedid in table_B it will be displayed but with NULL as relatedid in the results table.
with validids as (
select distinct id
from Table_A
inner join Table_B on
Table_A.relatedid = Table_B.relatedid
)
select
id,
relatedid
from Table_A
where id in (select id from validids)
union
select distinct
id,
null
from Table_A
where id not in (select id from validids)
Try:
Select Distinct Id, Related_Id
From Table_A
Where Related_Id In
(Select Related_Id From Table_B)
This should do what you want:
with IdsWithMatchInB(Id) as (
select distinct
Id
from Table_A
where Table_A.RelatedId in (
select Table_B.RelatedId
from Table_B
)
)
select
Table_A.Id,
CASE WHEN IdsWithMatchInB.Id IS NULL
THEN NULL
ELSE Table_A.RelatedId END AS RelatedId
from Table_A
left outer join IdsWithMatchInB
on IdsWithMatchInB.Id = Table_A.Id
Here's another option that avoids DISTINCT by putting the subquery inside the CASE expression:
select
Id,
case when Id in (
select Id
from Table_A as Acopy
where Acopy.RelatedId in (
select
RelatedId
from Table_B
)
)
then RelatedId
else null end as RelatedId
from Table_A;
One or the other might be more efficient for your particular data and indexes.