SQL copy value from once column to another based on a condition - sql

There are 4 columns in my SQL table:
+--------+----------+---------+--------+-----------+
|Column1 |Column2 |Column3 |Column4 |Column5 |
+--------+----------+---------+--------+-----------+
| 1 | abc | def | | 34654 |
| 2 | def | abc | | 798798 |
+--------+----------+---------+--------+-----------+
Goal is check if Column3 is in Column2, if it matches then fill Column4 with the respective value of Column1.
For example, "def" of Column3 matches "def" of Column2, so Column4 should be 2.
Desired output:
+--------+----------+---------+--------+-----------+
|Column1 |Column2 |Column3 |Column4 |Column5 |
+--------+----------+---------+--------+-----------+
| 1 | abc | def | 2 | 34654 |
| 2 | def | abc | 1 | 798798 |
+--------+----------+---------+--------+-----------+
I tried doing join on one of the tables like this:
SELECT a.Column1
, a.Column2
, a.Column3
, b.Column1 as Column4 FROM "table" a
LEFT JOIN "table" b on lower(a.Column3) = lower(b.Column2)
This creates a new Column4 when in my table Column4 already exists. I am doing UNION ALL of many tables and I need all my columns (32 in total) as the output.
How can I achieve this using SQL query?

in a SELECT
SELECT a.Column1
, a.Column2
, a.Column3
, case when Column2 = Column3
then Column1
else Column4 -- keep same value
end as Column4
, a.Column5
FROM "table" a
in an UPDATE
update "table"
set Column4 = case when Column2 = Column3
then Column1
else Column4 -- keep same value
end

Related

select SQL rows depending on non-identical results of a query

I am trying to select the columns which is relevant without knowing in advance which ones
I do a:
select *
from table
where id = '1'
the result i get is maybe 10 rows and 100+ columns
|id | column1 | column2 | column3 | column4 | column5 |....
| 1 | a | b | c | d | e |....
| 1 | a | XXX | c | d | e |....
| 1 | a | b | c | YYY | e |....
| 1 | a | b | c | d | e |....
For every row, one (or more) of the columns value is different, but i dont know which one(s)
is there any way i can create a temp table with the first query and do a sub query to display only one columns which doesnt have the same value in all the rows?
so the result would look like this:
|id | column2 | column4 |
| 1 | b | d |
| 1 | XXX | d |
| 1 | b | YYY |
| 1 | b | d |
since column 2 and 4 were the ones with non identical data these are the ones I want to see.
As already mentioned, this would require dynamic sql.
Maybe this will help you:
CREATE TABLE Column_Relevance
SELECT id,
COUNT(DISTINCT(column_1))/COUNT(*) AS relevance_column_1,
COUNT(DISTINCT(column_2))/COUNT(*) AS relevance_column_2,
COUNT(DISTINCT(column_3))/COUNT(*) AS relevance_column_3,
# AND SO ON....
GROUP BY id;
All relevance_columns with value < 1 indicate different values for the columns. You can build the whole statement in excel in a few minutes.
Once the table is created, add another column and create a select statement based on the column relevance (e.g. select if(relevance_column_1<1, column_1, else 'ignore') as column_1. This will return the string 'ignore' for all columns, that don't have distinct values.
This is far from perfect but maybe it helps you a little.
Here is a way you could use some aggregation to help. You said you have nearly 100 columns so this could take some effort to create but once it is done it would be fine. And this is just for analysis. You could utilize sys.columns to build the code for you but then we are back in the land of dynamic sql.
declare #Something table
(
ID int
, Column1 varchar(10)
, Column2 varchar(10)
, Column3 varchar(10)
, Column4 varchar(10)
, Column5 varchar(10)
)
insert #Something
values
(1, 'a', 'b', 'c', ' d ', 'e')
, (1, 'a', 'XXX', 'c', ' d ', 'e')
, (1, 'a', 'b', 'c', 'YYY', 'e')
, (1, 'a', 'b', 'c', ' d ', 'e')
;
with MinMax as
(
select ID
, MIN(Column1) as Col1Min
, MAX(Column1) as Col1Max
, MIN(Column2) as Col2Min
, MAX(Column2) as Col2Max
, MIN(Column3) as Col3Min
, MAX(Column3) as Col3Max
, MIN(Column4) as Col4Min
, MAX(Column4) as Col4Max
, MIN(Column5) as Col5Min
, MAX(Column5) as Col5Max
from #Something
group by ID
)
select s.ID
, Column1 = case when mm.Col1Max = mm.Col1Min then '' else s.Column1 end
, Column2 = case when mm.Col2Max = mm.Col2Min then '' else s.Column2 end
, Column3 = case when mm.Col3Max = mm.Col3Min then '' else s.Column3 end
, Column4 = case when mm.Col4Max = mm.Col4Min then '' else s.Column4 end
, Column5 = case when mm.Col5Max = mm.Col5Min then '' else s.Column5 end
from #Something s
join MinMax mm on mm.ID = s.ID
Have you tried using distinct ? It returns only unique rows:
select *
from table
where id = '1'
|id | column2 | column4 |
| 1 | a | a |
| 1 | a | a |
| 1 | b | d |
| 1 | b | d |
select distinct * from table where id= '1'
|id | column2 | column4 |
| 1 | a | a |
| 1 | b | d |
I hope this helps you.

How to group by one column, take max for each group, and retain information of the other groups?

I have data like this:
column1 column2 column3
A V 10
A Z 11
A X 11
And for each data in column1I want to find the maximum value in column3 and the corresponding value in column2. How do I do this in HIVE?
The closest thing I have is to do select column1, max(column3) from table group by column1. But, this doesn't add the corresponding information from column2. How do I get that as well?
Upon a tie in column3, I really don't care which value we pull from column2. Thanks.
I want the result to be:
column1 column2 column3
A Z 11
One way to do it would be using row_number. In case of ties, you would get an arbitrary value for column2.
select column1,column2,column3
from (
select t.*,row_number() over(partition by column1 order by column3 desc) as rn
from tablename t
) x
where rn=1
Here are some variation of the same concept
select column1 ,
,max(named_struct('column3',column3,'column2',column2)).column2
,max(column3) as column3
from mytable
group by column1
;
+---------+---------+---------+
| column1 | column2 | column3 |
+---------+---------+---------+
| A | Z | 11 |
+---------+---------+---------+
select column1
,max(struct(column3,column2)).col2 as column2
,max(column3) as column3
from mytable
group by column1
;
+---------+---------+---------+
| column1 | column2 | column3 |
+---------+---------+---------+
| A | Z | 11 |
+---------+---------+---------+
select column1
,col.column2
,col.column3
from (select column1
,max(named_struct('column3',column3,'column2',column2)) as col
from mytable
group by column1
) t
;
+---------+---------+---------+
| column1 | column2 | column3 |
+---------+---------+---------+
| A | Z | 11 |
+---------+---------+---------+

How to split two columns into two rows using oracle sql?

for example I have a data below:
column1 column2 column3 column4 column5
A B 5 2 3
My desired table would be:
columnA
A
B
The condition to determine the splitting is if (column3 + column4)>5 otherwise no splitting.
union all:
select column1 as columnA from t where column3 + column4 > 5
union all
select column2 from t where column3 + column4 > 5 ;
I'm not sure I fully understood what you are looking for, but if you wan' to put a if, ele in the SELECT, you might wan't to use the CASE expression.
https://docs.oracle.com/cd/B19306_01/server.102/b14200/expressions004.htm
Use a LEFT JOIN (with join condition) or CROSS JOIN (no join condition) to a derived table that consists of 2 rows, then output the values via a case expression. Both approaches allow access to all columns for other conditions too.
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TABLE1
(COLUMN1 VARCHAR2(1), COLUMN2 VARCHAR2(1), COLUMN3 INT, COLUMN4 INT, COLUMN5 INT)
;
INSERT ALL
INTO TABLE1 (COLUMN1, COLUMN2, COLUMN3, COLUMN4, COLUMN5)
VALUES ('A', 'B', 5, 2, 3)
INTO TABLE1 (COLUMN1, COLUMN2, COLUMN3, COLUMN4, COLUMN5)
VALUES ('C', 'D', 1, 1, 1)
SELECT * FROM DUAL
Query 1:
select
case when lj.rn = 1 then t.column1 else t.column2 end as columnA
, t.column1
, t.column2
, t.column3
, t.column4
, t.column5
from table1 t
left join ( select 1 as rn from dual union all select 2 from dual ) lj
on (column3 + column4) > 5
Results:
| COLUMNA | COLUMN1 | COLUMN2 | COLUMN3 | COLUMN4 | COLUMN5 |
|---------|---------|---------|---------|---------|---------|
| A | A | B | 5 | 2 | 3 |
| B | A | B | 5 | 2 | 3 |
| D | C | D | 1 | 1 | 1 |
Query 2:
select
case when cj.rn = 1 then t.column1 else t.column2 end as columnA
, t.column1
, t.column2
, t.column3
, t.column4
, t.column5
from table1 t
cross join ( select 1 as rn from dual union all select 2 from dual ) cj
Results:
| COLUMNA | COLUMN1 | COLUMN2 | COLUMN3 | COLUMN4 | COLUMN5 |
|---------|---------|---------|---------|---------|---------|
| A | A | B | 5 | 2 | 3 |
| B | A | B | 5 | 2 | 3 |
| C | C | D | 1 | 1 | 1 |
| D | C | D | 1 | 1 | 1 |
Suppose I have table test with sample data
column1 | column2 | column3 | column4 | column5
-------------------------------------------------------
A | B | 5 | 2 | 3
C | D | 1 | 1 | 1
E | F | 4 | 5 | 1
Script for above sample data:-
CREATE TABLE TEST
(
column1 VARCHAR2(10),
column2 VARCHAR2(10),
column3 NUMBER(2),
column4 NUMBER(2),
column5 NUMBER(2)
);
INSERT INTO TEST VALUES('A','B',5,2,3);
INSERT INTO TEST VALUES('C','D',1,1,1);
INSERT INTO TEST VALUES('E','F',4,5,1);
COMMIT;
Below query will give required output:-
WITH tmp AS
(SELECT (CASE
WHEN column3 + column4 > 5 THEN
column1||','||column2
ELSE
NULL
END) columna,
column1,column2,column3,column4,column5
FROM TEST)
SELECT regexp_substr(columna,'[^,]+',1,LEVEL) columna,
column1,column2,column3,column4,column5
FROM tmp
CONNECT BY LEVEL <= regexp_count(columna, ',') + 1
AND PRIOR column1 = column1
AND PRIOR dbms_random.random IS NOT NULL;
Output:
columnA | column1 | column2 | column3 | column4 | column5
-------------------------------------------------------------------
A | A | B | 5 | 2 | 3
B | A | B | 5 | 2 | 3
| C | D | 1 | 1 | 1
E | E | F | 4 | 5 | 1
F | E | F | 4 | 5 | 1

SQLite check if subquery gives same answers as other subquery

I need to construct query like this:
SELECT * FROM table1 AS t1 WHERE (
(SELECT column2 FROM table1 WHERE column1=t1.column1)!=(SELECT column2 FROM table1 WHERE column1=1)
)
But the problem is that SQLite checks only first results of subqueries.
I mean that if SELECT column2 FROM table1 WHERE column1=t1.column1 gives following results: (1,2,3) and SELECT column2 FROM table1 WHERE column1=1 gives (1,2,3,4) SQLite will check only 1!=1, not (1,2,3)!=(1,2,3,4).
I need to filter rows where prevoius two queries give only same rows (i.e. (1,2,3) from the first and (1,2,3) from the second)
The example of my table:
id | column1 | column2 | ...
1 | 1 | 1 | ...
2 | 1 | 2 | ...
3 | 1 | 3 | ...
4 | 2 | 1 | ...
5 | 2 | 2 | ...
6 | 2 | 3 | ...
7 | 2 | 4 | ...
8 | 3 | 1 | ...
9 | 3 | 2 | ...
10 | 3 | 3 | ...
And I need to get rows from id=4 to id=7 because it has 7 | 2 | 4 | ... row (for one column1 value there are not same column2 values as in column1)
You could try compound select statements: subtract the subqueries from each other and check if any row is left:
SELECT *
FROM table1 AS t1
WHERE EXISTS (SELECT column2 FROM table1 WHERE column1=t1.column1
EXCEPT
SELECT column2 FROM table1 WHERE column1=1)
OR EXISTS (SELECT column2 FROM table1 WHERE column1=1
EXCEPT
SELECT column2 FROM table1 WHERE column1=t1.column1)
Alternatively, do a similar operation with individual rows: the subqueries are different if some row does not have a counterpart in the other subquery:
SELECT *
FROM table1 AS t1
WHERE EXISTS (SELECT column2
FROM table1 AS t2
WHERE column1 = t1.column1
AND NOT EXISTS (SELECT 1
FROM table1 AS t3
WHERE column2 = t2.column2
AND column1 = 1))
OR EXISTS (SELECT column2
FROM table1 AS t2
WHERE column1 = 1
AND NOT EXISTS (SELECT 1
FROM table1 AS t3
WHERE column2 = t2.column2
AND column1 = t1.column1))
(The second query might be more efficient if you have the requisite indexes.)

SQL: Inner join with top 2 rows with second table from on condition

Hi I am now trying to join 2 table with only 2 rows from second table join to first table.
For example, I have following 2 tables:
**Table A**
Column1 | Column2 | Column3
A | B | 30
A | C | 50
A | D | 25
**Table B**
Column4 | Column5
B | 35
B | 90
B | 65
B | 80
B | 85
B | 40
C | 100
C | 60
C | 70
C | 65
Here is example of my normal query:
select *
from
(
select *
from A
where Column1 = 'A' and (Column2 = 'B' or Column2 = 'C')
order by Column2, Column3
) A
inner join
(
select *
from B
where (Column4 = 'B' or Column4 = 'C')
order by Column5
) B
on (A.Column2 = B.Column4 and ((B.Column5 - A.Column3) > 30))
The Result should look like:
**Result:**
Column1 | Column2 | Column3 | Column4 | Column5
A | B | 30 | B | 65
A | B | 30 | B | 80
A | B | 30 | B | 85
A | B | 30 | B | 90
A | C | 50 | C | 100
However, the result that I want is to join only 2 row from second table result only. The expected result should be:
**Expected Result:**
Column1 | Column2 | Column3 | Column4 | Column5
A | B | 30 | B | 65
A | B | 30 | B | 80
A | C | 50 | C | 100
Do anyone have idea of how to create such sql statement? Thank you.
You could use row_number() to limit the number of rows. The example assumes that (Column1, Column2, Column3) is unique. If table A has a primary key, use that instead.
select *
from (
select Column1
, Column2
, Column3
, Column4
, Column5
, row_number() over (partition by Column1, Column2, Column3
order by Column5 - Column3 desc) as rn
from A
join B
on A.Column2 = B.Column4
where Column1 = 'A'
and Column2 in ('B', 'C')
and Column5 - Column3 > 30
) SubQueryAlias
where rn < 2
See example at SQL Fiddle.
A good start would be to write more simple SQL without the inline views:
select *
from A inner join
B on (A.Column2 = B.Column4)
where A.Column1 = 'A' and
A.Column2 in ('B','C') and
(B.Column5 - A.Column3) > 30)
Try using a CTE
WITH Top2Rows AS (
SELECT TOP 2 *
FROM TableB
WHERE ([ADD CONSTRAINTS])
)
SELECT *
FROM TableA a
JOIN Top2Rows r ON a.ID = b.ID
WHERE ([ADD CONSTRAINTS])