Oracle SQL : Union and Joins [closed] - sql

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I have a table ACCPLAN(PRIMARY KEY : ACCOUNT_ID)
ACCOUNT_ID PLAN_TYPE OTHER_STUFF
ACC1 PLAN_TYPE_ONE ....
ACC2 PLAN_TYPE_TWO ....
ACC3 PLAN_TYPE_ONE ....
ACC4 PLAN_TYPE_TWO ...
I have one more table ACCTRANSACTION (PRIMARY KEY -> (ACCOUNT_ID,TRANSACTION_ID)
ACCOUNT_ID TRANSACTION_ID TRANSACTION_AMOUNT TXN_TYPE
ACC1 1 100 TXN_TYPE_1
ACC1 2 300 TXN_TYPE_2
ACC2 1 400 TXN_TYPE_2
ACC3 1 400 TXN_TYPE_3
There are 5 fixed plan_types and 20 fixed txn_types.Only few transactions types are
possible for each plan_type.(For eg : TXN_TYPE_1 and TXN_TYPE_2 are possible for
PLAN_TYPE_ONE and TXN_TYPE_2 and TXN_TYPE_3 are possible for PLAN_TYPE_TWO)
I am trying to retrieve the transaction information from ACCTRANSACTION and other
details from ACCPLAN
This can be done in 2 ways
APPROACH 1
Retrieve for each plan_type and do an union
select ap.account_id,ap.other_stuff,at.transaction_amount
from accplan ap, acctransaction at
where ap.account_id = at.account_id
and ap.plan_type = PLAN_TYPE_ONE
and at.txn_type in (TXN_TYPE_1,TXN_TYPE_2);
union
select ap.account_id,ap.other_stuff,at.transaction_amount
from accplan ap, acctransaction at
where ap.account_id = at.account_id
and ap.plan_type = PLAN_TYPE_TWO
and at.txn_type in (TXN_TYPE_2,TXN_TYPE_3);
union
...
APPROACH 2
Retrieve using one query for all plan_types
select ap.account_id,ap.other_stuff,at.transaction_amount
from accplan ap, acctransaction at
where ap.account_id = at.account_id
and
((ap.plan_type = PLAN_TYPE_ONE and at.txn_type in (TXN_TYPE_1,TXN_TYPE_2))
or
(ap.plan_type = PLAN_TYPE_TWO and at.txn_type in (TXN_TYPE_2,TXN_TYPE_3));
which approach is better considering both tables have huge data?. Please suggest.

Use joins. Unions require sorting the whole result and it is an expensive operation for your database.
Furthermore. It is better to read the table one time and do some complex checks with each record than reading it several times just to make smaller checks.
Disclaimer: I can imagine some very strange corner cases where the first query runs faster if the database query planner decides that the big condition is not selective enough and does not uses an index and each of the smaller one does use it. The bigger the number of rows the more I would use the second option.

Related

Nested SELECT vs JOIN performance [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 months ago.
Improve this question
I have the following two tables in PostgreSQL database (simplified for the sake of example):
article
id
summary
1
Article 1
2
Article 2
3
Article 3
...
...
event
id
article_id
eventtype_id
comment
108
1
4
Comment 1
109
2
8
Comment 2
110
3
4
Comment 3
...
...
I would like to select only 1 event with eventtype_id=4 for each article. The result should look like this:
article_id
article_summary
event_comment
1
Article 1
Comment 1
2
Article 2
3
Article 3
Comment 3
...
Which of these 2 queries (Query 1 or Query 2) runs faster? Do they return the same result?
Query1:
SELECT
a.id AS article_id,
a.summary AS article_summary,
evnt.comment AS event_comment
FROM
article a
LEFT JOIN
event evnt ON evnt.article_id = a.id AND evnt.eventtype_id = 4;
Query2:
SELECT
a.id AS article_id,
a.summary AS article_summary,
(
SELECT
evnt.comment
FROM
event evnt
WHERE
evnt.article_id = a.id AND
evnt.eventtype_id = 4
LIMIT 1
) AS event_comment
FROM
article a;
Apart from the fact that queries are not the same, as you said in the comments, generally speaking, correlated queries are not considered suitable from a performance point of view. That's because these queries are applied row by row. They are usually helpful in some particular situations: read this. However, even in those situations, it is a good practice to use them in an exists clause if possible, So that whenever it finds a row for the query it returns true.

SQL Server: DISTINCT with joins [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 months ago.
Improve this question
I want to print total number of orders of each state year-wise. But this is printing multiple states and not distinct.
SELECT DISTINCT
customer_state,
COUNT(*),
YEAR(order_purchase_timestamp) AS year
FROM
olist_orders_dataset
JOIN
olist_customers_dataset ON olist_orders_dataset.customer_id = olist_customers_dataset.customer_id
GROUP BY
YEAR(order_purchase_timestamp), customer_state
I am getting this output:
State
Year
Num_orders
AC
2020
123
AC
2020
1234
AC
2019
234
Here is the Required Output:
State
Year
Num_orders
AC
2020
19995
CA
2020
188891
AL
2019
11999
Firstly, I don't think it should be necessary to point out that your "output" doesn't match your query. Different column order and names. And somehow 2 rows for CA (123 and 1234) become 1 row (19995)? Math isn't that difficult. Simple oversights of that nature suggest a lack of effort.
Your output suggests that the two values you see as "AC" are not actually the same. Typically this means there is a trailing character that is not displayable (e.g., tab or linefeed). If that is the case, then you must first "fix" your data and then fix the process that is populating your table.
To verify that this is the problem, you can convert the column to varbinary to see the hex values stored in it. Example:
select customer_state, cast(customer_state as varbinary(20)) as bin_state, count(*)
from #tbl
where customer_state like 'AC%'
group by customer_state order by customer_state
;
fiddle to demonstrate. If my guess is correct, then there is an important lesson to learn. Stop throwing code into a query to fix a problem without understanding the cause.
And one last note. Aggregation tends to produce rows in some order. That is an artifact of the execution plans. If the order of rows in your resultset matters (and it usually does), the query MUST have an ORDER BY clause. That applies to every query - not just those using aggregation.

How to use Sum() function with condition? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I have an Access database. There is a table named cost with bottom value:
reson Cost Type
------------ ------ ------
A1 2500 1
A1 6500 1
A2 95000 2
A3 2500 1
A1 6500 1
A4 50000 2
Now I want a query that calculate sum of all cost filed where type = 2 and sum of cost filed where type = 1 and substract the first value from the second value.
For example, the above pic calculate final result:
Sum of Type 2 = 145000
Sum of Type 1 = 18000
-------------------------
Final Result = 127000
My Sql Code
select iif(type = 2, sum(cost), -sum(cost)) As col1 from cost group by type
First off, I'm sorry you have to deal with such obnoxious hostility when asking your question here. You asked your question perfectly fine, laying out your table structure, and your desired result. It's understandable that you are new to queries and need help creating them. Not every answer requires code, and not every person knows where to start.
Here is your answer:
Step 1
Make sure you have your table created with the data you provided
Step 2
Create a new query named qySumType1. Build it like this, so it sums everything of type=1. make sure to click the totals button.
Step 3
Create another query, name this one qySumType2. This query should sum everything of type=2.
Step 4
Now create another query called "Final". Add both of your previous queries to it. Now create an expression in the last column to calculate the difference between the 2 numbers. Just like this.
And there you have it. Now just run the Final query anytime you want to get the difference.
Hope this helps! I can't tell you how many times I've started learning something new and relied on a community to help me get started. Always just try your best and wait for a decent answer to your question. Good luck!
Change T1 to the name of your table.
SELECT Sum(T.Type1) AS Type1, Sum(T.Type2) AS Type2, Sum(T.Type2) - Sum(T.Type1) AS DIFF
FROM
(
SELECT Sum(T1.Cost) AS Type1, 0 AS Type2
FROM T1
WHERE (((T1.Type)=1))
UNION
SELECT 0 AS Type1, Sum(T1.Cost) AS Type2
FROM T1
WHERE (((T1.Type)=2))
) AS T;
Type1 | Type2 | DIFF
18000 | 145000 | 127000

transpose some SQL columns into rows [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
ID YEAR FORCE NEIGHBOURHOOD ALL_CRIME ANTI_SOCIAL_BEHAVIOUR BURGLARY CRIMINAL_DAMAGE_AND_ARSON DRUGS OTHER_THEFT PUBLIC_DISORDER_AND_WEAPONS ROBBERY SHOPLIFTING VEHICLE_CRIME VIOLENT_CRIME OTHER_CRIME
1 2013-03 Police AAN_HP 290 91 27 33 11 64 8 6 3 14 27 6
i need to change the order of theses into something like
ID 1
YEAR 2012
FORCE Police
NEIGHBOURHOOD Bradford
ALL_CRIME 12345
ANTI_SOCIAL 87
BURGLARY 10
CRIMINAL_DAMAGE 20
DRUGS 15
OTHER_THEFT 30
If you want to changed the order in which the columns are returning change the order in which you are selecting them
SELECT 1,2,3 FROM t
Would return differently from
SELECT 2,1,3 FROM t
I don't know if this is what you wanted but I found the question confusingly worded!
Quite easy to do with a query:
with lvls as (select /* + materialize */ level lv from dual connect by level <= 9)
select id,
decode(lv,
1,'year',
2,'force'),
...
decode(lv,
1,to_char(year),
2,to_char(force),
...
from yourtable, lvls
order by id,lv;
hint "materialize" will not make Oracle be unperformant (he likes to join here the tables first and then run hierarchy if you do not specify this hint)
try this
select * from your_tab unpivot(col2 for col1 in(ID,YEAR,FORCE,NEIGHBOURHOOD, ALL_CRIME,ANTI_SOCIAL_BEHAVIOUR);
note:All columns mentioned in col1 must be of same datatype

Select Query to find difference [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I am fairly new to sql. my question is how do I group by a field and then determine the difference between values in a column. for example.
claim# amount
1. c3101 50000
2. c3101 19000
3. c1307 30000
4. c1307 14000
5. c3104 75000
6. c3104 0
7. c1313 5000
8. c1313 10000
expected results
1. c3101 -31000
2. c1307 -26000
3. c1313 5000
i need to find the diffence between amounts relative to a claim number. so for c3101 i started at 50000 and went to 19000 so the transaction to get to 19000 would be -31000. c3104 would be ignored
You can use group by and sum to find the total values for a specific claim.
Finding the difference cannot be done unless you specify which claim amount was the first (unless you use the insertion/default order).
If we know which is first we could subtract with the other amount (or amount(s)).
If there are only two entries for each claim you can get the absolute different between the first() and last() entries.
select claim, abs(last(amount) - first(amount)) from claims group by claim;
You can also get the non-absolute difference, based on insertion order:
select claim, (last(amount) - first(amount)) from claims group by claim;
Update
As first() and last() are not supported in many DBs, below are alternatives:
MySQL
select distinct claim,
(select amount from claims c1 where c1.claim = c2.claim limit 1,1) -
(select amount from claims c1 where c1.claim = c2.claim limit 0,1) as "Difference"
from claims c2;
SQLFiddle: http://sqlfiddle.com/#!2/2e62a0/15
MS SQL
For MS SQL, as it is quite more difficult to get the bottom X records from a set, I make use of the average() function:
SELECT claim, ((avg(amount)*2) -
(SELECT top 1 amount
FROM claims c2
WHERE c2.claim = c.claim))-
(SELECT top 1 amount
FROM claims c2
WHERE c2.claim = c.claim)
FROM claims c
GROUP BY claim;
which is further simplified to:
SELECT claim,
2* ( avg(amount) -
(SELECT top 1 amount
FROM claims c2
WHERE c2.claim = c.claim))
FROM claims c
GROUP BY claim;
SQL Fiddle: http://sqlfiddle.com/#!3/2e62a/28