Create a duplicate row on top of Select statement - sql

table TEST
id
Name
1
abc
2
xyz
In general i used to get records from below query
Select id,name from TEST.
id
Name
1
abc
2
xyz
but now i want to create a duplicate for each row on top my select query
expected output: please suggest how can i achieve result like below
id
Name
1
abc
1
abc
2
xyz
2
xyz

You may cross join your table with a sequence table containing how ever many copies you want. Here is an example using an inline sequence table:
SELECT t1.id, t1.Name
FROM yourTable t1
CROSS JOIN (
SELECT 1 AS seq FROM dual UNION ALL
SELECT 2 FROM dual UNION ALL
SELECT 3 FROM dual
) t2
WHERE t2.seq <= 2
ORDER BY t1.id;

To me, UNION (ALL) set operator seems to be quite simple.
Sample data:
SQL> select * from test;
ID NAME
---------- ----
1 abc
2 xyz
UNION ALL:
SQL> select * from test
2 union all
3 select * from test;
ID NAME
---------- ----
1 abc
2 xyz
1 abc
2 xyz
SQL>

CREATE table test(
id integer,
name VARCHAR2(4)
);
INSERT into test (id, name) VALUES (1,'ABC');
INSERT into test (id, name) VALUES (2,'XYZ');
with data as (select level l from dual connect by level <= 2)
select *
from test, data
order by id, l
/

One more option is LATERAL
SELECT t.*
FROM test
, LATERAL (
SELECT id, name FROM DUAL
union all
SELECT id, name FROM DUAL
) t

One option is using a self-join along with ROW_NUMBER analytic function such as
WITH t AS
(
SELECT t1.id, t1.name, ROW_NUMBER() OVER (PARTITION BY t1.id ORDER BY 0) AS rn
FROM test t1,
test t2
)
SELECT id, name
FROM t
WHERE rn <= 2
Demo

Related

How to use subquery to drop rows from Tab1 which are in Tab2 in Oracle SQL?

I have tables in Oracle SQL like below:
Tab1
ID
-----
1
2
3
Tab2
ID
-----
3
4
5
And I need to take values from Tab1 which are not in Tab2. I made query like below:
select ID
from Tab1
where ID not in (select ID from Tab2)
Above query does not work, how can I change it to achieve result as I need:
ID
---
1
2
I can add that I prefere to use subquery in this problem, how can I do that in Oracle SQL ?
With the MINUS set operator:
SQL> with
2 tab1 (id) as
3 (select 1 from dual union all
4 select 2 from dual union all
5 select 3 from dual
6 ),
7 tab2 (id) as
8 (select 3 from dual union all
9 select 4 from dual union all
10 select 5 from dual
11 )
12 select id from tab1
13 minus
14 select id from tab2;
ID
----------
1
2
SQL>
BTW, query you used (with a subquery) returns correct result; did you mean to say that you prefer NOT to use a subquery?
<snip>
12 select id from tab1
13 where id not in (select id from tab2);
ID
----------
1
2
I tried this code and it worked fine :
select ID
from Table1
where ID not in (select ID from Table2)
You cant DROP rows from a table, but you can DELETE them.
So correcting you title to
How to use subquery to DELETE rows from Tab1 which are in Tab2 in Oracle SQL?
do so:
delete from tab1
where id in (select id from tab2);
1 row deleted.
select * from tab1;
ID
----------
1
2
Do not forget to commit to make the change permanent.

Hive: Populate other columns based on unique value in a particular column

I have a two tables in hive as mentioned below in Hive
Table 1:
id name value
1 abc stack
3 abc overflow
4 abc foo
6 abc bar
Table 2:
id name value
5 xyz overflow
9 xyz stackoverflow
3 xyz foo
23 xyz bar
I need to take the count of value column without considering the id and name column.
Expected output is
id name value
1 abc stack
9 xyz stackoverflow
I tried this and works in other databases but not in hive
select id,name,value from
(SELECT id,name,value FROM table1
UNION ALL
SELECT id,name,value FROM table2) t
group by value having count(value) = 1;
Hive expects group by clause like mentioned below.
select id,name,value from
(SELECT id,name,value FROM table1
UNION ALL
SELECT id,name,value FROM table2) t
group by id,name,value having count(value) = 1;
and gives the output
id name value
1 abc stack
3 abc overflow
4 abc foo
6 abc bar
5 xyz overflow
9 xyz stackoverflow
3 xyz foo
23 xyz bar
We will have to give all the columns in group by which we are using in select clause. but when i give it considers all the columns and the result is different than expected.
Calculate analytic count(*) over(partition by value).
Testing with your data example:
with
table1 as (
select stack (4,
1,'abc','stack',
3,'abc','overflow',
4,'abc','foo',
6,'abc','bar'
) as (id, name, value)
),
table2 as (
select stack (4,
5, 'xyz','overflow',
9, 'xyz','stackoverflow',
3, 'xyz','foo',
23, 'xyz','bar'
) as (id, name, value)
)
select id, name, value
from(
select id, name, value, count(*) over(partition by value) value_cnt
from
(SELECT id,name,value FROM table1
UNION ALL
SELECT id,name,value FROM table2) s
)s where value_cnt=1;
Result:
OK
id name value
1 abc stack
9 xyz stackoverflow
Time taken: 55.423 seconds, Fetched: 2 row(s)
You can try below -
seELECT id,name,value FROM table1 a left join table2 b on a.value=b.value
where b.value is null
UNION ALL SELECT
seELECT id,name,value FROM table2 a left join table1 b on a.value=b.value
where b.value is null

How to select a single row multiple times in PostgreSql

I want to print 4 times the same row in PostgreSQL, how to achieve that ?
Table : mytable
Id | name
------------
1 | foo
2 | bar
3 | zzz
I want something like
Select 4x mytable.* from mytable where id=1
And the result should be
Id | name
------------
1 | foo
1 | foo
1 | foo
1 | foo
You can cross join against generate_series(1,4), which will return a table containing the numbers 1 to 4:
SELECT mytable.*
FROM mytable
CROSS JOIN generate_series(1,4) as x
WHERE id=1
For each row in your original result set, there will be one copy with 1 next to it, one with 2, and so on.
you can use generate_series.
sample:
t=# create table so48 (i int,n text);
CREATE TABLE
t=# insert into so48 select 1,'a';
INSERT 0 1
t=# insert into so48 select 2,'b';
INSERT 0 1
select:
t=# with s as (select generate_series(1,4,1) g) select so48.* from so48 join s on true where i = 1;
i | n
---+---
1 | a
1 | a
1 | a
1 | a
(4 rows)
use union all
Select mytable.* from mytable where id=1
union all Select mytable.* from mytable where id=1
union all Select mytable.* from mytable where id=1
union all Select mytable.* from mytable where id=1
Cross join should do the job
Select 4x mytable.* from mytable where id=1
cross join
(select 1 from dual union all
select 1 from dual union all
select 1 from dual union all
select 1 from dual )

Max rows by group

Current SQL:
select t1.*
from table t1
where t1.id in ('2', '3', '4')
Current results:
id | seq
---+----
3 | 5
2 | 7
2 | 5
3 | 7
4 | 3
Attempt to select maxes:
select t1.*
from table t1
where t1.id in ('2', '3', '4')
and t1.seq = (select max(t2.seq)
from table2 t2
where t2.id = t1.id)
This obviously does not work since I'm using an in list. How can I adjust my SQL to get these expected results:
id | seq
---+----
2 | 7
3 | 7
4 | 3
Group By is your friend:
SELECT
id,
MAX(seq) seq
FROM TABLE
GROUP BY id
EDIT: Response to comment. To get the rest of the data from the table matching the max seq and id just join back to the table:
SELECT t1.*
FROM TABLE t1
INNER JOIN (
SELECT
id
MAX(seq) as seq
FROM TABLE
GROUP BY id
) as t2
on t1.id = t2.id
and t1.seq = t2.seq
EDIT: Gordon and Jean-Francois are correct you can also use the ROW_NUMBER() analytic function to get the same result. You need to check the performance difference for your application (I did not check). Here is an example of that:
SELECT *
FROM (
SELECT ROW_NUMBER() OVER (
PARTITION BY id
ORDER BY seq DESC) as row_num
,*
FROM TABLE
) as TMP
WHERE row_num = 1
This SQL Query will give you max seq from individaul ID.
SELECT t1.*
FROM t1
WHERE t1.id in ('2', '3', '4')
AND NOT EXISTS (
SELECT *
FROM t1 t2
WHERE t2.id = t1.id
AND t2.seq > t1.seq
select *
from table
where (id,seq) in
(
select id,max(seq)
from table
group by id
having id in ('2','3','4')
);
That is if id and/or seq are completely part of the PK of that table.
Here's another example, using the first/last method I mentioned earlier in the comments:
with sd as (select 3 id, 5 seq, 1 dummy from dual union all
select 2 id, 7 seq, 2 dummy from dual union all
select 2 id, 5 seq, 3 dummy from dual union all
select 3 id, 7 seq, 4 dummy from dual union all
select 3 id, 7 seq, 5 dummy from dual union all
select 4 id, 3 seq, 6 dummy from dual)
select id,
max(seq) max_seq,
max(dummy) keep (dense_rank first order by seq desc) max_rows_dummy
from sd
group by id;
ID MAX_SEQ MAX_ROWS_DUMMY
---------- ---------- --------------
2 7 2
3 7 5
4 3 6
The keep (dense_rank first order by ...) bit is requesting to keep the values associated with the rank of 1 in the order list of rows. The max(...) bit is there in case more then one row has a rank of 1; it's just a way of breaking ties.

oracle intersection with or without distinct

I have following query:
select id from t1
intersect
select id from t2
intersect
select id from t3
id could be non unique in some tables, so I need to use distinct.
In general what is better:
select distinct id from (
select id from t1
intersect
select id from t2
intersect
select id from t3)
or
select distinct id from t1
intersect
select id from t2 -- here id is unique
intersect
select distinct id from t3
There is no need for the DISTINCT. The INTERSECT operator automatically produces a distinct set of values. As you can see in this example, x has two rows with an ID of 1, y only has one row with an ID of 1 and the INTERSECTION of the two produces just a single row
SQL> ed
Wrote file afiedt.buf
1 with x as (select 1 id from dual union all select 1 from dual),
2 y as (select 1 id from dual)
3 select id
4 from x
5 intersect
6 select id
7* from y
SQL> /
ID
----------
1
Even if you take the INTERSECT of the two row table with itself, you still get a single row in the output
SQL> ed
Wrote file afiedt.buf
1 with x as (select 1 id from dual union all select 1 from dual)
2 select id
3 from x
4 intersect
5 select id
6* from x
SQL> /
ID
----------
1