How to join two query in SQL (Oracle) - oracle9i

How can I join these queries?
SELECT RCTDT, SUM(RCTAMOUNT), COUNT(RCTAMOUNT) FROM RECEIPTS4
WHERE RCTDT BETWEEN '01-nov-2009' AND '30-nov-2009'
AND RCTTYPE='CA' AND RCTAMOUNT>0
GROUP BY RCTDT
---
SELECT RCTDT, SUM(RCTAMOUNT), COUNT(RCTAMOUNT) FROM RECEIPTS4
WHERE RCTDT BETWEEN '01-nov-2009' AND '30-nov-2009'
AND RCTTYPE='CQ' AND RCTAMOUNT>0
GROUP BY RCTDT

Use the IN operator:
SELECT RCTDT, SUM(RCTAMOUNT), COUNT(RCTAMOUNT) FROM RECEIPTS4
WHERE RCTDT BETWEEN '01-nov-2009' AND '30-nov-2009'
AND RCTTYPE IN ('CA','CQ') AND RCTAMOUNT>0
GROUP BY RCTDT

Maybe you meant this
SELECT RCTDT,
SUM(case when rcttype='CA' then RCTAMOUNT else null end) as CASUM,
COUNT(case when rcttype='CA' then RCTAMOUNT else null end) as CACOUNT,
SUM(case when rcttype='CQ' then RCTAMOUNT else null end) as CQSUM,
COUNT(case when rcttype='CQ' then RCTAMOUNT else null end) as CQCOUNT,
FROM RECEIPTS4
WHERE RCTDT BETWEEN '01-nov-2009' AND '30-nov-2009'
AND RCTTYPE in('CA','CQ') AND RCTAMOUNT>0
GROUP BY RCTDT

In this particular example, use an IN as suggested by cletus. In other cases, where the two result sets cannot be generated from the same select, use a UNION to combine the results:
SELECT something FROM somewhere
UNION
SELECT something FROM somewhere_else

SELECT RCTDT, SUM(RCTAMOUNT), COUNT(RCTAMOUNT) FROM RECEIPTS4
WHERE RCTDT BETWEEN '01-nov-2009' AND '30-nov-2009'
AND RCTTYPE IN ('CA','CQ') AND RCTAMOUNT>0
GROUP BY RCTDT
can also be useful.

Related

Trying to fetch data from table with good performance

I am trying to fetch customer and owner data
customer
|cnumber |id |
|080204220 |32859471000|
|907501981|6029151000|
role
|id|type|
|32859471000|owner|
|6029151000|customer|
result set
id|number|owner number|type|
|32859471000|080204220 |080204220 | owner
|6029151000|907501981|080204220 |customer
query
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
left outer join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id ) sub on sub.roletype='owner';
This query gives proper result, but left outer join with same tables may cause impact on performance, is there any other way to achieve this?
I would prefer you to go with this only.
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
left outer join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id ) sub on sub.roletype='owner';
As far as I can get the logic, you need to display an "owner"-customer among all of the others.
Since there is only one owner in the example data, I'd do it using the "cross join" (cartesian join)
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
cross join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id where r.roletype='owner') sub
select c.id,sub.cnumber,c.cnumber, r.roletype
from customer c
inner join role r on c.id = r.id
left outer join (select c.cnumber ,r.roletype,c.id
from customer c
INNER JOIN role r
ON c.id = r.id ) sub on sub.roletype='owner';

How to use group by in Informix?

I'm going to use the group by clause...max().
I'm using Informix version 10.
This is example table: table_a
col_a col_b col_c
1 20181010 3
1 20181030 4
I want to retrieve data with a recent date.
I want result :
col_a col_b col_c
1 20181030 4
When I use this query
#query 1: select col_a, max(col_b), col_c from table_a group by col_a
#result : The column (col_c) must be in the GROUP BY list.
#query 2: select col_a, max(col_b), col_c from table_a group by col_a, col_c
#result :
col_a col_b col_c
1 20181010 3
1 20181030 4
I think can I use MS SQL of row_num(partition by col_b)? but
Informix version 10 can't use row_num...
So, I use a join query
select a.col_a,a.col_b,a.col_c from table_a a
inner join (select col_a, max(col_b) as col_b from table_a group by col_a) b
on a.col_a = b.col_a and a.col_b = b.col_b
I got the results I wanted.
Is there a way to use join?

Re-write a query to avoid PG::GroupingError: ERROR: in the GROUP BY clause or be used in an aggregate function

I tried many alternatives before posting this question.
I have a query on a table A with columns: id, num, user_id.
id is PK, user_id can be duplicate.
I need to have all the rows such that only unique user_id has chosen to have highest num value. For this, I came up with aSQL below, which will work in Oracle database. I am on ruby on rails platform with Postgres Database.
select stats.* from stats as A
where A.num > (
select B.num
from stats as B
where A.user_id == B.user_id
group by B.user_id
having B.num> min(B.num) )
I tried writing this query via active record method but still ran into
PG::GroupingError: ERROR: column "b.num" must appear in the GROUP BY
clause or be used in an aggregate function
Stat.where("stats.num > ( select B.nums from stats as B where stats.user_id = B.user_id group by B.user_id having B.num < max(B.num) )")
Can someone tell me alternative way of writing this query
The SELECT clause of your subquery in Rails doesn't match that of your example. Note that since you're performing an aggregate function min(B.num) in your HAVING clause, you'll have to also include it in your SELECT clause:
Stat.where("stats.num > ( select B.num from stats as B where stats.user_id = B.user_id group by B.user_id having B.num < max(B.num) )")
You may also need a condition to handle the case where select B.num from stats as B where stats.user_id = B.user_id group by B.user_id having B.num < max(B.num) returns more than one row.

Using multiple column names in where with RoR and ActiveRecord

I want to produce the following sql using active record.
WHERE (column_name1, column_name1) IN (SELECT ....)
I don't know how to do this is active record.
I've tried these so far
where('column_name1, column_name2' => {})
where([:column_name1, :column_name2] => {})
This is the full query I'd like to create
SELECT a, Count(1)
FROM table
WHERE ( a, b ) IN (SELECT a,
Max(b)
FROM table
GROUP BY a)
GROUP BY a
HAVING Count(1) > 1)
I've already written a scope for the subquery
Thanks in advance.
WHERE (column_name1, column_name1) IN (SELECT ....) is not a valid construct in sql; so it can't be done in active record either.
The valid way of accomplishing the same in SQL would be:
WHERE column_name1 IN (select ....) OR column_name2 IN (select ...)
The same query can be used directly in the active record:
where("column_name1 IN (select ...) OR column_name2 IN (select...)")
Avoiding duplication:
selected_values = select ...
where("column_name IN ? OR column_name2 in ?", selected_values, selected_values)
So I decided to use an inner join to gain the same functionality. Here is my solution.
select(:column1, 'Count(1)').
joins("INNER JOIN (#{subquery.to_sql}) AS table2 ON
table1.column1=table2.column1
AND table1.column2=table2.column2")

Nested query in squeel

Short version: How do I write this query in squeel?
SELECT OneTable.*, my_count
FROM OneTable JOIN (
SELECT DISTINCT one_id, count(*) AS my_count
FROM AnotherTable
GROUP BY one_id
) counts
ON OneTable.id=counts.one_id
Long version: rocket_tag is a gem that adds simple tagging to models. It adds a method tagged_with. Supposing my model is User, with an id and name, I could invoke User.tagged_with ['admin','sales']. Internally it uses this squeel code:
select{count(~id).as(tags_count)}
.select("#{self.table_name}.*").
joins{tags}.
where{tags.name.in(my{tags_list})}.
group{~id}
Which generates this query:
SELECT count(users.id) AS tags_count, users.*
FROM users INNER JOIN taggings
ON taggings.taggable_id = users.id
AND taggings.taggable_type = 'User'
INNER JOIN tags
ON tags.id = taggings.tag_id
WHERE tags.name IN ('admin','sales')
GROUP BY users.id
Some RDBMSs are happy with this, but postgres complains:
ERROR: column "users.name" must appear in the GROUP BY
clause or be used in an aggregate function
I believe a more agreeable way to write the query would be:
SELECT users.*, tags_count FROM users INNER JOIN (
SELECT DISTINCT taggable_id, count(*) AS tags_count
FROM taggings INNER JOIN tags
ON tags.id = taggings.tag_id
WHERE tags.name IN ('admin','sales')
GROUP BY taggable_id
) tag_counts
ON users.id = tag_counts.taggable_id
Is there any way to express this using squeel?
I wouldn't know about Squeel, but the error you see could be fixed by upgrading PostgreSQL.
Some RDBMSs are happy with this, but postgres complains:
ERROR: column "users.name" must appear in the GROUP BY clause or be
used in an aggregate function
Starting with PostgreSQL 9.1, once you list a primary key in the GROUP BY you can skip additional columns for this table and still use them in the SELECT list. The release notes for version 9.1 tell us:
Allow non-GROUP BY columns in the query target list when the primary
key is specified in the GROUP BY clause
BTW, your alternative query can be simplified, an additional DISTINCT would be redundant.
SELECT o.*, c.my_count
FROM onetable o
JOIN (
SELECT one_id, count(*) AS my_count
FROM anothertable
GROUP BY one_id
) c ON o.id = counts.one_id

Resources