I have to display about 5 columns from 2 database tables using the Group By clause as follows:
SELECT T1.COLUMN_A, T1.COLUMN_B, T1.COLUMN_C, SUM(T2.COLUMN_D)
FROM TABLE1 T1, TABLE2 T2
WHERE T1.COLUMN_A = T2.COLUMN_A
GROUP BY T1.COLUMN_A
Now COLUMN_B has the same value across all the rows having the same COLUMN_A and COLUMN_B is a amount field.
COLUMN_C is a date field and would be same across the same COLUMN_A values.
Ex. Here is dummy data TABLE T1
COLUMN_A COLUMN_B COLUMN_C
1 $25 09/15/2911 12:00:00 AM
1 $25 09/15/2011 12:00:00 AM
2 $20 12/12/2011 12:00:00 AM
...
TABLE T2:
COLUMN_A COLUMN_D
1 $100
1 $10
2 $200
2 $200
.....
Running the query does not work with following error: ORA-00979: not a GROUP BY expression
Removing COLUMN_B and COLUMN_C would work. However I need these columns as well.
Can anyone please suggest the required changed?
This should work
SELECT T1.COLUMN_A, T1.COLUMN_B, T1.COLUMN_C, SumColumnD
FROM TABLE1 T1
INNER JOIN
(SELECT COLUMN_A, SUM(COLUMN_D) AS SumColumnD
FROM TABLE2 T2
GROUP BY COLUMN_A) t ON T1.COLUMN_A = t.COLUMN_A
If the values of COLUMN_B and COLUMN_C are the same across same values of COLUMN_A, then you can simply add them to theGROUP BY clause:
SELECT T1.COLUMN_A, T1.COLUMN_B, T1.COLUMN_C, SUM(T2.COLUMN_D)
FROM TABLE1 T1, TABLE2 T2
WHERE T1.COLUMN_A = T2.COLUMN_A
GROUP BY T1.COLUMN_A, T1.COLUMN_B, T1.COLUMN_C
You've specified columns COLUMN_B and COLUMN_C in your SELECT list, so Oracle will need to provide a value for them when GROUPing BY COLUMN_A. However. Oracle doesn't know that these columns are constant across same values of COLUMN_A, and you get the error because in general it has no way of returning a value for these columns.
Adding COLUMN_B and COLUMN_C to the GROUP BY clause shouldn't affect the results of the query and should allow you to use them in your SELECT list.
Related
Could you please help me below query.
Table 1 (Input)had three columns (Credit_date, Debit_date, Payment_date) and
Table 2 (Output) has one column date
The three column values from Table 1 should be available in Table 2.
I tried below query but not working.
insert into table2
select date
from (
(select credit_date, debit_date, Payment_date from table 1) as date)t;
Could you please guide.
Try doing a union all:
insert into table2
select * from (
select credit_date as date from table1
union all
select debit_date as date from table1
union all
select payment_date as date from table1
) t
So I have 4 different tables and I want to put them in one table with one of the columns from the tables and the # of times a particular value appears in that column. All the columns are strings.
For example:
table A
col1
20190204
20190204
20190204
20190205
20190205
20190205
Table B
col1
20200204
20200204
20200204
20200204
20200205
20200205
20200205
TableC
col1
20210204
20210204
20210204
20210204
20210205
20210205
20210205
TableD
col1
20220204
20220204
20220204
20220204
20220205
20220205
20220205
TableE -- All the 4 tables will go into here
TableE is empty and needs to be populated with the dates from the other tables and the number of times they occur in those tables. For example:
col1(tablea) col2 col3(tbaleb) col4 col5(tablec) col6
20190204 4 20200204 4 20210204 4
20190205 3 20200205 3 20210205 3
col7(tabled) col8
20220205 3
20220205 4
etc...
I am new to hue, so I tried something like this:
insert overwrite into tablee (
tablee.tablea.date, tablee.tablea.datecount,
tablee.tablebdate, tablee.tableb.datecount,
tablee.tablecdate, tablee.tablec.datecount,
tablee.tableddate, tablee.tablea.datedcount,
select tablea.date, count(tablea.date),
tableb.date, count(tableb.date),
tablec.date, count(tablec.date),
tabled.date, count(tabled.date)
)
from tablea, tableb, tablec, tabled
left join tablee on (tablea.date=tablee.date)
left join tablee on (tableb.date=tablee.date)
left join tablee on (tablec.date=tablee.date)
left join tablee on (tabled.date=tablee.date);
But I am not able to get it to work correctly. Does anyone have any tips?
Please check if below query gives your desired result set.
select * from (select col1,count(*) from tablea group by 1)a
full outer join
(select col1,count(*) from tableb group by 1)b on a.col1=b.col1
full outer join
(select col1,count(*) from tablec group by 1)c on b.col1=c.col1
full outer join
(select col1,count(*) from tabled group by 1)d on c.col1=d.col1;
First all the grouped data from each table is calculated and then we doing full outer join to include all values of col1 from each table to get result set. Finally if the result set is what the desired one we can convert select statement to insert into/overwrite statement.
I have a requirement to do matching of few attributes one by one. I'm looking to avoid multiple select statements. Below is the example.
Table1
Col1|Price|Brand|size
-----------------------
A|10$|BRAND1|SIZE1
B|10$|BRAND1|SIZE1
C|30$|BRAND2|SIZE2
D|40$|BRAND2|SIZE4
Table2
Col1|Col2|Col3
--------------
B|XYZ|PQR
C|ZZZ|YYY
Table3
Col1|COL2|COL3|LIKECOL1|Price|brand|size
-----------------------------------------
B|XYZ|PQR|A|10$|BRAND1|SIZE1
C|ZZZ|YYY|D|NULL|BRAND2|NULL
In table3, I need to insert data from table2 by checking below conditions.
Find a match for record in table2, if Brand and size, Price match
If no match found, then try just Brand, Size
still no match found, try brand only
In the above example, for the first record in table2, found match with all the 3 attributes and so inserted into table3 and second record, record 'D' is matching but only 'Brand'.
All I can think of is writing 3 different insert statements like below into an oracle pl/sql block.
insert into table3
select from tab2
where all 3 attributes are matching;
insert into table3
select from tab2
where brand and price are matching
and not exists in table3 (not exists is to avoid
inserting the same record which was already
inserted with all 3 attributes matched);
insert into table3
select from tab2
where Brand is matching and not exists in table3;
Can anyone please suggest a better way to achieve it in any better way avoiding multiple times selecting from table2.
This is a case for OUTER APPLY.
OUTER APPLY is a type of lateral join that allows you join on dynamic views that refer to tables appearing earlier in your FROM clause. With that ability, you can define a dynamic view that finds all the matches, sorts them by the pecking order you've specified, and then use FETCH FIRST 1 ROW ONLY to only include the 1st one in the results.
Using OUTER APPLY means that if there is no match, you will still get the table B record -- just with all the match columns null. If you don't want that, you can change OUTER APPLY to CROSS APPLY.
Here is a working example (with step by step comments), shamelessly stealing the table creation scripts from Michael Piankov's answer:
create table Table1 (Col1,Price,Brand,size1)
as select 'A','10','BRAND1','SIZE1' from dual union all
select 'B','10','BRAND1','SIZE1' from dual union all
select 'C','30','BRAND2','SIZE2' from dual union all
select 'D','40','BRAND2','SIZE4'from dual
create table Table2(Col1,Col2,Col3)
as select 'B','XYZ','PQR' from dual union all
select'C','ZZZ','YYY' from dual;
-- INSERT INTO table3
SELECT t2.col1, t2.col2, t2.col3,
t1.col1 likecol1,
decode(t1.price,t1_template.price,t1_template.price, null) price,
decode(t1.brand,t1_template.brand,t1_template.brand, null) brand,
decode(t1.size1,t1_template.size1,t1_template.size1, null) size1
FROM
-- Start with table2
table2 t2
-- Get the row from table1 matching on col1... this is our search template
inner join table1 t1_template on
t1_template.col1 = t2.col1
-- Get the best match from table1 for our search
-- template, excluding the search template itself
outer apply (
SELECT * FROM table1 t1
WHERE 1=1
-- Exclude search template itself
and t1.col1 != t2.col1
-- All matches include BRAND
and t1.brand = t1_template.brand
-- order by match strength based on price and size
order by case when t1.price = t1_template.price and t1.size1 = t1_template.size1 THEN 1
when t1.size1 = t1_template.size1 THEN 2
else 3 END
-- Only get the best match for each row in T2
FETCH FIRST 1 ROW ONLY) t1;
Unfortunately is not clear what do you mean when say match. What is you expectation if there is more then one match?
Should it be only first matching or it will generate all available pairs?
Regarding you question how to avoid multiple inserts there is more then one way:
You could use multitable insert with INSERT first and condition.
You could join table1 to self and get all pairs and filter results in where condition
You could use analytical function
I suppose there is another ways. But why you would like to avoid 3 simple inserts. Its easy to read and maintain. And may be
There is example with analytical function next:
create table Table1 (Col1,Price,Brand,size1)
as select 'A','10','BRAND1','SIZE1' from dual union all
select 'B','10','BRAND1','SIZE1' from dual union all
select 'C','30','BRAND2','SIZE2' from dual union all
select 'D','40','BRAND2','SIZE4'from dual
create table Table2(Col1,Col2,Col3)
as select 'B','XYZ','PQR' from dual union all
select'C','ZZZ','YYY' from dual
with s as (
select Col1,Price,Brand,size1,
count(*) over(partition by Price,Brand,size1 ) as match3,
count(*) over(partition by Price,Brand ) as match2,
count(*) over(partition by Brand ) as match1,
lead(Col1) over(partition by Price,Brand,size1 order by Col1) as like3,
lead(Col1) over(partition by Price,Brand order by Col1) as like2,
lead(Col1) over(partition by Brand order by Col1) as like1,
lag(Col1) over(partition by Price,Brand,size1 order by Col1) as like_desc3,
lag(Col1) over(partition by Price,Brand order by Col1) as like_desc2,
lag(Col1) over(partition by Brand order by Col1) as like_desc1
from Table1 t )
select t.Col1,t.Col2,t.Col3, coalesce(s.like3, like_desc3, s.like1, like_desc1, s.like1, like_desc1),
case when match3 > 1 then size1 end as size1,
case when match1 > 1 then Brand end as Brand,
case when match2 > 1 then Price end as Price
from table2 t
left join s on s.Col1 = t.Col1
COL1 COL2 COL3 LIKE_COL SIZE1 BRAND PRICE
B XYZ PQR A SIZE1 BRAND1 10
C ZZZ YYY D - BRAND2 -
I've got a table as follows
Table1
ID Name Tag
-----------------
1 N1 2.1
2 N2 3.5
3 N1 3.5
4 N3 8.1
I create a new table Table2 with ID and Name (unique constraint) and I want to insert Table1's contents into Table2 avoiding duplicates, in the sense that I want only 1, 2 and 4 from Table1 in Table2.
I've tried this but it doesn't seem to work and I get the unique constraint error (ORACLE SQL)
INSERT INTO TABLE2 (ID, NAME)
SELECT ID, NAME
FROM TABLE1
WHERE NAME NOT IN (SELECT NAME FROM TABLE2);
Please can someone point me in the right direction?
Sorry for not making myself clear. Table2 is a brand new table. I want the first values inserted, the following duplicates should be ignored. So in my case, N1, N2 get inserted, N1 is dupe so it is ignored, N3 is inserted
OK - from your description, I understand table t2 is currently empty, and you want to copy the rows where id is in (1, 2, 4) from table t1 to table t2.
Why your code fails:
You seem to believe that the condition is applied to the first row in t1, it passes so it is inserted into t2, then the condition is applied to the second row in t1 (using what is already inserted in t2), etc. - and you don't understand why there is any attempt to insert ALL the rows from t1 into t2. Why doesn't the third row fail the WHERE clause?
Good question! The reason is that operations are done on a SET basis. The WHERE condition uses table t2 AS IT WAS before the INSERT operation began. So for ALL rows, the WHERE clause compares to an empty table t2.
How to fix this... Decide which id you want to add when there are duplicate names. For example, one way to get the result you said you wanted is to select MIN(id) for each name. Moreover, you still want to check if the name exists in t2 already (since you may do this again in the future, when t2 is already partially populated).
insert into t2 ( id, name )
select min(id), name
from t1
where name not in (select name from t2)
group by name
;
You can try it bother....!
Insert into tb2(Field1, Field2)
SELECT Field1, Field2
FROM tb1
WHERE NOT EXISTS (SELECT Field1 FROM tb1) ;
This is how I understood the question:
SQL> create table table2
2 (id number,
3 name varchar2(2),
4 tag number,
5 constraint pk_t2 primary key (id, name)
6 );
Table created.
SQL>
SQL> insert into table2 (id, name, tag)
2 with test (id, name, tag) as
3 (select 1, 'N1', 2.1 from dual union
4 select 2, 'N2', 3.5 from dual union
5 select 3, 'N1', 3.5 from dual union
6 select 4, 'N3', 8.1 from dual
7 )
8 select min(id), name, max(tag)
9 from test
10 group by name;
3 rows created.
SQL>
SQL> select * from table2 order by id;
ID NA TAG
---------- -- ----------
1 N1 3,5
2 N2 3,5
4 N3 8,1
SQL>
When we need to unique any two or more column we have to create unique index.
Run this query
ALTER TABLE TABLE2 ADD UNIQUE unique_index( id, name);
and then
INSERT INTO TABLE2 (id,name,tag) VALUES(1, "N1", 3.5 )
ON DUPLICATE KEY UPDATE tag=3.5
this will also help to update new tag
Try to check if the id and name from Table1 is doesn't exist in Table2, if then insert.
If the unique constraint on TABLE2 is a composite key then run this:
INSERT INTO TABLE2 (ID, NAME)
SELECT A.ID, A.NAME
FROM TABLE1 A
WHERE NOT EXISTS (SELECT NULL FROM TABLE2 B WHERE A.ID=B.ID AND A.NAME=B.NAME);
If there are two unique constraints; one on the id, and the other on the name then run this instead:
INSERT INTO TABLE2 (ID, NAME)
SELECT A.ID, A.NAME
FROM TABLE1 A
WHERE NOT EXISTS (SELECT NULL FROM TABLE2 B WHERE A.ID=B.ID OR A.NAME=B.NAME);
ORACLE, in case you need to get values from 2 different tables.
below example,i use an increment case.
INSERT INTO TABLE1
(INDEX, REMARKS, NAME, AGE)
(SELECT (SELECT colescs(MAX(INDEX),0) FROM TABLE1)+1,
'any remarks',
t2.NAME, t2,age from TABLE2 t2 where t2.name = 'apple')
explanation
match below numbers (1)-(1), (2)-(2) ...
INSERT INTO TABLE1
(INDEX, //index increment (1)
REMARKS, //hard code (2)
NAME, //from table2 (3)
AGE) //from table2 (4)
(SELECT // this part is to get values from another table
(SELECT colescs(MAX(INDEX),0) FROM TABLE1)+1, //increment (1)
'any remarks', //hard code value (2)
t2.NAME, //from table2 (3)
t2,age //from table2 (4)
from TABLE2 t2 where t2.name = 'apple') //condition for table2
Here my question: I have a table with some records like (name, date, type). Suppose I have three type a, b and c.Now I want to count percentage of each type mean COUNT(type)/COUNT(table row count)??
select type,COUNT(type) as counttype,counttype/(select COUNT(*) from xyz) from xyz group by xyz;
"(select COUNT(*) from xyz)" this giving me error.
How to find the table Row Count?
You can use below query :-
select A.type,A.type_cnt,(A.type_cnt/B.total_cnt) from
(Select type,count(type) as type_cnt from xyz group by type)A
JOIN
(select count(*)as total_cnt from xyz)B
ON 1=1;
Without JOIN it is much faster, using analytic function:
select type,
count(type) as type_cnt,
count(type)/count(*) over() as pct
from xyz
group by type;