How to loop select statement based on the previous select statement? - sql

I need all the data to be in one straight line.
I need to create a report and for that i need to summarize all.
So i did this select statement first.
Query1
Select t1.scn,t1.vsl_name, t1.act_arr_dt_tm, t1.act_dept_dt_tm, t1.del_remarks
from vesvoy t1
So based on the select statement above i need to get all the t1.scn to loop the below sql
Query2
Select t1.scn,t2.void_flg,
MAX(case when t2.inv_num like 'VI%' then t2.inv_num end) as Vessel,
MAX(case when t2.inv_num like 'VI%' then t2.inv_amt end) as Vessel_amt
from pbosinvoiceitem t1
inner join pbosinvoice t2 ON t2.id = t1.master_id
inner join pbosinvtype t4 ON t4.code = t2.inv_type
group by t1.scn,t2.void_flg
so that i can get the result like in the report. I have try to create temp table but the data that i get is all duplicate.
I try combining both queries but the result shows duplicate result

I'm sitting here thinking: "What does the first query have to do with the second?" Both are on the same table, vesvoy, so what could the question be. The second is processing the same rows as the first.
I suspect the issue is that the joins are losing rows. So, I suspect that the answer is use left join, rather than inner join. Along the way, get rid of the select distinct. This is generally a bad idea. In combination with a group by on the same non-aggregated columns, it just shows a lack of awareness of SQL.
So, does this address your concern?
SELECT t1.scn,
MAX(case when t3.inv_num like 'VI%' then t3.inv_num end) as Vessel,
MAX(case when t3.inv_num like 'VI%' then t3.inv_amt end) as Vessel_amt
FROM vesvoy t1 LEFT JOIN
pbosinvoiceitem t2
ON t2.scn = t1.scn LEFT JOIN
pbosinvoice t3
ON t3.id = t2.master_id
GROUP BY t1.scn;
This will return NULL for the non-matching rows.

Related

sql - ignore duplicates while joining

I have two tables.
Table1 is 1591 rows. Table2 is 270 rows.
I want to fetch specific column data from Table2 based on some condition between them and also exclude duplicates which are in Table2. Which I mean to join the tables but get only one value from Table2 even if the condition has occurred more than time. The result should be exactly 1591 rows.
I tried to make Left,Right, Inner joins but the data comes more than or less 1591.
Example
Table1
type,address,name
40,blabla,Adam
20,blablabla,Joe
Table2
type,currency
40,usd
40,gbp
40,omr
Joining on 'type'
Result
type,address,name,currency
40,blabla,name,usd
20,blblbla,Joe,null
try this it has to work
select *
from
Table1 h
inner join
(select type,currency,ROW_NUMBER()over (partition by type order by
currency) as rn
from
Table2
) sr on
sr.type=h.type
and rn=1
Try this. It's standard SQL, therefore, it should work on your rdbms system.
select * from Table1 AS t
LEFT OUTER JOIN Table2 AS y ON t.[type] = y.[type] and y.currency IN (SELECT MAX(currency) FROM Table2 GROUP BY [type])
If you want to control which currency is joined, consider altering Table2 by adding a new column active/non active and modifying accordingly the JOIN clause.
You can use outer apply if it's supported.
select a.type, a.address, a.name, b.currency
from Table1 a
outer apply (
select top 1 currency
from Table2
where Table2.type = a.type
) b
I typical way to do this uses a correlated subquery. This guarantees that all rows in the first table are kept. And it generates an error if more than one row is returned from the second.
So:
select t1.*,
(select t2.currency
from table2 t2
where t2.type = t1.type
fetch first 1 row only
) as currency
from table1 t1;
You don't specify what database you are using, so this uses standard syntax for returning one row. Some databases use limit or top instead.

Optimization of DB2 query which uses joins and takes 1.5 hours to execute

when i run SELECT stataement on my view it takes around 1.5 hours to run, what can i do to optimize it.
Below is the sample structure of how my view looks like
CREATE VIEW SCHEMANAME.VIEWNAME
{
COL, COL1, COL2, COL3 }
AS SELECT
COST.ETA,
CASE
WHEN VOL.CURR IS NOT NULL
THEN COALESCE {VOL.COMM,0}
END CASE,
CASE
WHEN...
END CASE
FROM TABLE1 t1 inner join TABLE2 t2 ON t1.ETA=t2.ETA
INNER JOIN TABLE3 t3 on t2.ETA=t3.ETA
LEFT OUTER JOIN TABLE4 t4 on t2.ETA=t4.ETA
This is your query:
SELECT COST.ETA,
(CASE WHEN VOL.CURR IS NOT NULL THEN COALESCE {VOL.COMM,0}
END) as ??,
. . .
FROM TABLE1 t1 inner join
TABLE2 t2
ON t1.ETA = t2.ETA INNER JOIN
TABLE3 t3
on t2.ETA = t3.ETA LEFT OUTER JOIN
TABLE4 t4
on t2.ETA = t4.ETA;
First, I will the fact that the select clause references tables that are not in the from clause. I assume this is a typo.
Second, you should be able to use indexes to improve this query: table1(eta), table2(eta),table3(eta), andtable4(eta).
Third, I am highly suspicious on seeing the same column used for joining so many tables. I suspect that you might have cartesian products occurring, because there are multiple values of any given eta in several tables. If that is the case, you need to fix the query to better reflect what you really need. If so, ask another question with sample data and desired results, because your query is probably not correct.

How to do full join on one field and inner join on another from same table

I have a query something like the following:
select sum(t1.qty) t1Total, sum(t2.qty) t2Total, sum(t1.qty - t2.qty) difference
from t1 full join
t2 on t1.date = t2.date and t1.chain = t2.chain
I want it to do an full join on the date, but an inner join on the chain. In other words, one table has chains the other doesn't and I don't want the extra chains to be included in the total, but I do want to make sure that all days from a chain that's in both tables are accounted for.
What's the easiest way to do that?
Use a case statement inside the sums; set it to zero when the chain is null on the inner table. Eg:
sum(case when t2.chain is null then 0 else t1.qty end) as t1Total

Where Exists query returning incorrect results

The inner query here returns values that only appear in one of the tables. The outer query is supposed to return a count of those. Instead, it returns the entire table, not just the NULL values.
select count(*) from tblicd
where exists
(
select i.icd_id
from tblicd i left outer join icd_jxn on icd_jxn.icd_id=i.icd_id
where icd_jxn.icd_id is null
)
The inner query
select i.icd_id
from tblicd i left outer join icd_jxn on icd_jxn.icd_id=i.icd_id
where icd_jxn.icd_id is null
works and does what I want. I'd like (using a sub query method like this) to use the outer query to just return the number of rows that the inner query returns.
You need to join the two (outer and inner) tblicd tables in the subquery:
and i.icd_id = tblicd.icd_id
(or whatever the id of the tblicd table is)
The query you posted doesn't make any sense. However, from your description, it sounds like you've got two tables and you're trying to find any IDs that don't exist in both tables. If that's correct, you should try something like this:
select count(*) as cnt
from table1 t1
full outer join
table2 t2
on t1.id = t2.id
where t1.id is null
or t2.id is null
This may not work in the database you're using, but since you didn't tell us that, we can't tailor the solution to fit your dialect of SQL.
Based on the revised question, you could simplify this a number of ways:
select count(*)
from tblicd
where not exists (select i.icd_id
from icd_jxn
where icd_jxn.icd_id = tblicd)
select count(tblicd.icd_id)
from tblicd
left join
icd_jxn
on tblicd.icd_id = icd_jxn.icd_id
where icd_jxn.icd_id is null
select count(tblicd.icd_id)
from tblicd
where icd_id not in (select icd_id
from icd_jxn)
Basically, there's no reason to select from tblicd twice.

SQLite table aliases effecting the performance of queries

How does SQLite internally treats the alias?
Does creating a table name alias internally creates a copy of the same table or does it just refers to the same table without creating a copy?
When I create multiple aliases of the same table in my code, performance of the query is severely hit!
In my case, I have one table, call it MainTable with namely 2 columns, name and value.
I want to select multiple values in one row as different columns. for example
Name: a,b,c,d,e,f
Value: p,q,r,s,t,u
such that a corresponds to p and so on.
I want to select values for names a,b,c and d in one row => p,q,r,s
So I write a query
SELECT t1.name, t2.name, t3.name, t4.name
FROM MainTable t1, MainTable t2, MainTable t3, MainTable t4
WHERE t1.name = 'a' and t2.name = 'b' and t3.name = 'c' and t4.name = 'd';
This way f writing the query kills the performance when size of the table increases as rightly pointed above by Larry.
Is there any efficient way to retrieve this result. I am bad at SQL queries :(
If you list the same table more than once in your SQL statement and do not supply conditions on which to JOIN the tables, you are creating a cartesian JOIN in your result set and it will be enormous:
SELECT * FROM MyTable A, MyTable B;
if MyTable has 1000 records, will create a result set with one million records. Any other selection criteria you include will then have to be evaluated across all one million records.
I'm not sure that's what you're doing (your question is very unclear), but it may be a start on solving your problem.
Updated answer now that the poster has added the query that is being executed.
You're going to have to get a little tricky to get the results you want. You need to use CASE and MAX and, unfortunately, the syntax for CASE is a little verbose:
SELECT MAX(CASE WHEN name='a' THEN value ELSE NULL END),
MAX(CASE WHEN name='b' THEN value ELSE NULL END),
MAX(CASE WHEN name='c' THEN value ELSE NULL END),
MAX(CASE WHEN name='d' THEN value ELSE NULL END)
FROM MainTable WHERE name IN ('a','b','c','d');
Please give that a try against your actual database and see what you get (of course, you want to make sure the column name is indexed).
Assuming you have table dbo.Customers with a million rows
SELECT * from dbo.Customers A
does not result in a copy of the table being created.
As Larry pointed out, the query as it stands is doing a cartesian product across your table four times which, as you has observed, kills your performance.
The updated ticket states the desire is to have 4 values from different queries in a single row. That's fairly simple, assuming this syntax is valid for sqllite
You can see that the following four queries when run in serial produce the desired value but in 4 rows.
SELECT t1.name
FROM MainTable t1
WHERE t1.name='a';
SELECT t2.name
FROM MainTable t2
WHERE t2.name='b';
SELECT t3.name
FROM MainTable t3
WHERE t3.name='c';
SELECT t4.name
FROM MainTable t4
WHERE t4.name='d';
The trick is to simply run them as sub queries like so there are 5 queries: 1 driver query, 4 sub's doing all the work. This pattern will only work if there is one row returned.
SELECT
(
SELECT t1.name
FROM MainTable t1
WHERE t1.name='a'
) AS t1_name
,
(
SELECT t2.name
FROM MainTable t2
WHERE t2.name='b'
) AS t2_name
,
(
SELECT t3.name
FROM MainTable t3
WHERE t3.name='c'
) AS t3_name
,
(
SELECT t4.name
FROM MainTable t4
WHERE t4.name='d'
) AS t4_name
Aliasing a table will result a reference to the original table that exists for the duration of the SQL statement.