SQL to find rows where two columns have the same value - sql

I have 3 columns in Oracle database having table mytable and i want records having only duplicate values in 2nd and 3rd column.
SQL> select * from mytable ;
column1 column2 column3
A 50 50----required output
A 10 20----have different values i.e. 10 and 20
A 50 50----required output
A 30 70----have different values i.e. 30 and 70
B 20 20----required output
B 40 30----have different values i.e. 40 and 30
I want the following output with count(*):
column1 column2 column3
A 50 50
A 50 50
B 20 20
Any help is much appreciated

select column1, count (*)
from mytable
where column2 = column3
group by column1, column2;

From your question it is not clear about primary key as A in First Column is being repeated many times.
You can try the following:
select column1, column2, column3, count(*) from
mytable where column2 = column3 group by column1, column2, column3;

Here are sample example , i am doing this SQL Server but i am sure this query work in ORACLE also
EXAMPLE :
Create table #Test (colA int not null, colB int not null, colC int not null, id int not null identity) on [Primary]
GO
INSERT INTO #Test (colA,colB,colC) VALUES (1,1,1)
INSERT INTO #Test (colA,colB,colC) VALUES (1,1,1)
INSERT INTO #Test (colA,colB,colC) VALUES (1,1,1)
INSERT INTO #Test (colA,colB,colC) VALUES (1,2,3)
INSERT INTO #Test (colA,colB,colC) VALUES (1,2,3)
INSERT INTO #Test (colA,colB,colC) VALUES (1,2,3)
INSERT INTO #Test (colA,colB,colC) VALUES (4,5,6)
GO
Select * from #Test
GO
select count(colA) as tot_duplicate_count , colA ,colB ,colC from #Test where id <=
(Select Max(id) from #Test t where #Test.colA = t.colA and
#Test.colB = t.colB and
#Test.colC = t.colC)
group by colA ,colB ,colC
having count(colA) > 1
This query this total count of duplicate record per data row

Related

Transform SQL Server table based on calculation

I have a table like below
Column1
Column2
A
200
A
200
A
0
B
300
B
200
C
100
I would like to transform this table into the following table
With calculation: for each element of column1, SUM (column2) / count of (non-zero column2)
Column1
Column2
A
((200+ 200 + 0) / 2) = 200
B
((300 + 200) / 2) = 250
C
100 / 1 = 100
The only thing I can think of is looping through distinct elements of Column1 and run:
SELECT SUM(Column2)
FROM Table
WHERE Column1 = i / (SELECT COUNT(Column2)
FROM Table
WHERE Column1 = i AND Column2 <> 0)
and generate a table.
Is there a better way of doing this?
Use aggregation:
SELECT Column1,
SUM(Column2) / COUNT(CASE WHEN Column2 <> 0 THEN 1 END) AS Column2
FROM yourTable
GROUP BY Column1
HAVING COUNT(CASE WHEN Column2 <> 0 THEN 1 END) > 0;
You can use where clause to remove rows with 0 in column2 then use aggregation to have your desired result. But it will remove those column1 values which have 0 in all columnd2.
But Query2 will return rows with zero values in column2 instead of removing the removing the row.
Schema and insert statements:
create table testTable (Column1 varchar(50), Column2 int);
insert into testTable values('A', 200);
insert into testTable values('A', 200);
insert into testTable values('A', 0);
insert into testTable values('B', 300);
insert into testTable values('B', 200);
insert into testTable values('C', 100);
insert into testTable values('D', 0);
Query1:
SELECT Column1,
SUM(Column2) / COUNT(*) AS Column2
FROM testTable where column2<>0
GROUP BY Column1;
Output:
Column1
Column2
A
200
B
250
C
100
Query2:
SELECT Column1,
Coalesce(SUM(Column2) / nullif(COUNT(CASE WHEN Column2 <> 0 THEN 1 END),0),0) AS Column2
FROM testTable
GROUP BY Column1;
Output:
Column1
Column2
A
200
B
250
C
100
D
0
db<>fiddle here
You can go for derived table to filter out the 0 column2 rows. Then, you can apply GROUP BY.
declare #table table (Column1 char(1), Column2 int)
insert into #table values
('A',200),
('A',200),
('A',0 ),
('B',300),
('B',200),
('C',100);
SELECT Column1, (sum(column2) / count(column2) ) as column2
from
(
SELECT * FROM #TABLE where Column2 <> 0) as t
group by Column1
Column1
column2
A
200
B
250
C
100
Retrieve distinct value of column1 and ignore zero value of column2 while division with total sum of column2. And also consider here divide by zero error.
-- SQL Server
SELECT t.column1
, t.column2 / (CASE WHEN (t.total - t.total_zero) = 0 THEN 1 ELSE (t.total - t.total_zero) END)
FROM (SELECT column1
, SUM(column2) column2
, COUNT(CASE WHEN column2 = 0 THEN 1 END) total_zero
, COUNT(1) total
FROM test
GROUP BY column1) t
Please check this url https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=3853456941909ffffb8792415adc1f6f
Use AVG() window function because you want the average value of Column2.
If you want all the values of Column1 in the results even if they have only 0s in Column2:
SELECT DISTINCT Column1,
AVG(CASE WHEN Column2 <> 0 THEN Column2 END) OVER (PARTITION BY Column1) Column2
FROM tablename;
If you want results for the values of Column1 that have at least 1 Column2 not 0:
SELECT DISTINCT Column1,
AVG(Column2) OVER (PARTITION BY Column1) Column2
FROM tablename
WHERE Column2 <> 0;
See the demo.
Note that SQL Server truncates the average of integers to an integer, so if you want the result as a floating point number you should multiply Column2 by 1.0, like:
AVG(CASE WHEN Column2 <> 0 THEN 1.0 * Column2 END)
or:
AVG(1.0 * Column2)

How to Match a string against patterns in Oracle SQL

I have a bit of different scenario. there is one column (Oracle table) in the table which stores patterns.another column with unique id.
Now, i have to match those patterns against a string and have to find out which patterns are matching that string.then i have to pick out those matched patterns along with the ids
Can anybody guide me on how to efficiently do it?
Sample Data
Table 1
-------
Column1 Column2
1 AB%
2 A%
3 %c%
Now, there is a string comes like ABC (take it as an item number. It gets inserted in DB and then a trigger fires that has to do the rest of the job as provided in sample below)
Table 2
---------
Column1 Column2
ABC AB%,A%
or more efficient(desired) Table 2 would be like -
Table 2(desired)
---------
Column1 Column2
ABC 1,2
This is the desired result.
In Oracle 11g you could use function listagg
and simple before insert or update trigger:
Sample data:
create table table1 (column1 number(3), column2 varchar2(10));
insert into table1 values (1, 'AB%');
insert into table1 values (2, 'A%');
insert into table1 values (3, '%c%');
create table table2 (column1 varchar2(10), column2 varchar2(500));
Trigger:
create or replace trigger tg_table2_ins
before insert or update of column1 on table2 for each row
declare
v_list table2.column2%type;
begin
select listagg(t1.column1, ', ') within group (order by t1.column1)
into v_list from table1 t1
where :new.column1 like t1.column2;
:new.column2 := v_list;
end tg_table2_ins;
Test:
insert into table2 (column1) values ('ABC');
insert into table2 (column1) values ('Oracle');
insert into table2 (column1) values ('XYZ');
insert into table2 (column1) values ('Ascii');
select * from table2;
COLUMN1 COLUMN2
---------- ----------
ABC 1, 2
Oracle 3
XYZ
Ascii 2, 3

dynamic columns in Query Or view

Please Help me. How can i show dynamic columns in Query. I want a view.
Thanks in advance
My Out is like this.
select SectionID,
Column1, Column2, Column3
from
(
select S.SectionID,ColumnDataName, ColumnDescription,
row_number() over(partition by S.SectionID
order by SectionTableColumnID) seq
from dbo.SectionTableColumn vt
INNER JOIN dbo.Section S ON S.SectionID = vt.SectionID
) d
pivot
(
max(ColumnDescription)
for ColumnDataName in ( Column1, Column2, Column3)
) piv;
it is not possible to create a view with a dynamic number of columns. You need to specify all the values of ColumnDataName in order for this to work.
You need to pivot your result, here is an example how you can create your view:
CREATE TABLE
xxx(SectionID int, ColumnDescription varchar(10), ColumnDataName varchar(10))
INSERT xxx values(2, 'dgj', 'column1')
INSERT xxx values(2, 'ash', 'column2')
INSERT xxx values(8, 'lkhsdh', 'column2')
go
CREATE VIEW v_xxx as
SELECT SectionId, [column1],[column2],[column3]
FROM xxx
PIVOT
(min(ColumnDescription)
FOR ColumnDataName
in([column1],[column2],[column3])
)AS p
go
SELECT * FROM v_xxx
Result:
SectionId column1 column2 column3
2 dgj ash NULL
8 NULL lkhsdh NULL

INSERT INTO subtract 2 values

Is it possible for an INSERT query to subtract 2 values you have entered to create a 3rd value that can then be inserted into a table - if that makes sense...
e.g.
INSERT INTO table1 (column1, column2, column3)
VALUES ('50', '25', column1 - column2)
INSERT INTO table1 (column1, column2, column3)
(select ('50', '25', column1 - column2) from table1 where conditions)
This is a sample query! hope it helps!
Convoluted:
INSERT INTO table1 (column1,column2,column3)
select column1,column2,column1-column2
from
(select 50 as column1,
25 as column2
) t
Since you can't reference other columns from the same SELECT clause, you have to do it as a subquery. I've also switched to using int literals rather than strings, because I can't make subtraction make sense in my head otherwise.
You could also do it using a Table Value Constructor:
INSERT INTO table1 (column1,column2,column3)
select column1,column2,column1-column2
from
( VALUES (50, 25)
) AS t (column1, column2);
As indicated in my comment though, if the relationship should always hold, I'd build table1 as:
CREATE TABLE table1 (
column1 int not null,
column2 int not null,
column3 as column1 - column2
--More columns
)
Because that way, the column3 value is always correct.
You can create function that subtracts values and use this function in insert. This is the right way to do such things:
INSERT INTO table1 (column1, column2, column3)
(select ('50', '25', your_function() ) from table1 where conditions)
/
Using the "INSERT INTO" would do this:
INSERT INTO Table1Name (column1, column2, column3,)
(select 'X', 'Y', X - Y as Z)
Here is a link to SQL Authority with more examples of INSERT INTO
Another method would to be add a trigger to the table, where on insert of data, the third column would be updated with the difference of the first two columns.

combining resultset of many select queries

I have four Select queries for four different tables, each extracting only one record. For example:
Select * from table where col1 = 'something'
gives one row having 3 columns.
The second select query also gives one record having two columns(fields). Same for third and fourth select query.
I want to combine all four result sets into one having one row. How is it possible?
I will write the queries for you.
1st one:
Select Top 1 column1, column2
from table 1
where column 1 = 'something'
and col1 = (Select max(col1) where column 1 = 'something')
2nd query:
Select Top 1 column1, column3
from table 2
where column 1 = 'something'
and column3 = (Select max(column3) where column 1 = 'something')
3rd query uses the result obtained from query 2:
Select column4
from table 3
where column3 = (obtained from 2nd query) (there is only one row)
4th:
Select column5
from table 4
where column3 = (obtained from 2nd query) (there is only one row)
This means I have to join 2nd, 3rd, 4th query, then resulting set in 1st.
I can't use union since columns are different.
So only problem is with joining the result set.
You can use CROSS JOINs to accomplish this.
CREATE TABLE table1 (id int, column1 varchar(5), column2 varchar(15));
CREATE TABLE table2 (column3 varchar(5), column4 varchar(15));
CREATE TABLE table3 (id int, column5 varchar(5), column6 varchar(15));
INSERT INTO table1 VALUES (1, 'aaa', 'row1')
INSERT INTO table2 VALUES ('bbb', 'table2')
INSERT INTO table3 VALUES (1, 'ccc', 'table3')
INSERT INTO table1 VALUES (1, 'ddd', 'table1')
SELECT * FROM (SELECT * FROM table1) a
CROSS JOIN (SELECT * FROM table2) b
CROSS JOIN (SELECT * FROM table3) c
Result:
id column1 column2 column3 column4 id column5 column6
1 aaa row1 bbb table2 1 ccc table3
1 ddd table1 bbb table2 1 ccc table3
Update after clarification:
CREATE TABLE table1
(
id int IDENTITY(1,1)
, searchstring nvarchar(25)
);
CREATE TABLE table2
(
id2 int IDENTITY(10, 10)
, searchstring2 nvarchar(25)
, newsearchstring nvarchar(50)
);
CREATE TABLE table3
(
id3 int IDENTITY(100, 100)
, id2 int
, table3srow nvarchar(25)
)
INSERT INTO table1 VALUES ('something');
INSERT INTO table1 VALUES ('something else');
INSERT INTO table1 VALUES ('something'); -- ID = 3, this row will be selected by 1st query
INSERT INTO table2 VALUES ('something', 'newvalue1');
INSERT INTO table2 VALUES ('something else', 'this will not be shown');
INSERT INTO table2 VALUES ('something', 'this will be returned by query 2'); -- ID = 30, this row will be selected by 2nd query
INSERT INTO table3 VALUES (10, 'not relevant');
INSERT INTO table3 VALUES (20, 'not relevant');
INSERT INTO table3 VALUES (30, 'This is from table 3'); -- This row will be returned by 3rd query
SELECT * FROM
(SELECT TOP 1 id, searchstring FROM table1 WHERE searchstring = 'something' and id = (SELECT MAX(id) FROM table1 WHERE searchstring = 'something')) AS query1,
(SELECT TOP 1 id2, newsearchstring FROM table2 WHERE searchstring2 = 'something' and id2 = (SELECT MAX(id2) FROM table2 WHERE searchstring2 = 'something')) AS query2,
(SELECT id2, table3srow FROM table3) as query3
WHERE query3.id2 = query2.id2
Use the same approach for table4 as indicated for table3.