Using UNION in SQL with queries and subqueries - sql

I am using the following code to try to UNION two sets of data, although it runs without error, it is running for over 10 minutes and not returning results so Im wondering if there is something Ive done wrong?
select BIH.SourceCode, BIH.MarketValueAmt as CorrectedAmt
from [dbo].[IRA_HIST] as BIH
JOIN
(select accountno, accountclass
from accounttable
where accountclass in ('A','B','C','D')) AS AccountNos
ON BIH.ACCOUNTNO = ACCOUNTNOS.ACCOUNTNO
where BIH.securityno > '0'
UNION
SELECT SourceCode, (Amount*(-1)) as CorrectedAmt
from accttable a, activitytable b
where a.accountclass in ('A','B','C','D')
and b.recordtype in ('r','c')
Any guidance is so helpful.

Since there are no other computations and transformations needed in data from accounttable, you can directly join it with ira_hist and no need to have the sub-query. Also, you need to have this ON a.[key column] = b.[key column] -- probably accountno on your join in your second query
SELECT BIH.SourceCode,
BIH.MarketValueAmt AS CorrectedAmt
FROM [dbo].[IRA_HIST] BIH
JOIN accounttable AccountNos
ON BIH.ACCOUNTNO = ACCOUNTNOS.ACCOUNTNO
AND BIH.securityno > '0'
AND AccountNos.accountclass in ('A','B','C','D')
UNION -- or UNION ALL if you want to retain duplicates
SELECT SourceCode,
(Amount*(-1)) as CorrectedAmt
FROM accttable a,
JOIN activitytable b
ON a.[key column] = b.[key column] -- probably accountno
AND a.accountclass IN ('A','B','C','D')
AND b.recordtype IN ('r','c')

In your 2nd SELECT, since you are querying the same table twice, you should be able to JOIN on a common key (e.g. FROM TABLE a JOIN TABLE b ON a.cKey = b.cKey).
Or, you could simplify that 2nd SELECT:
FROM TABLE WHERE AccountClass IN ('A', 'B',...) OR RecordType IN ('r', 'c')

Related

Writing a query

I have a task to write a query who will list all data from multiple tables.
So i have:
Table1 with ID and some other columns
Table2 with ID, ID_ Table1 and some other columns
Table3 with ID and some other columns. But Table3 is not related with the other two tables. Also number of rows are not the same.
So i need to get a result like this:
column from Table3, column from Table2 and new column which i will get if I compare the results from Table3 and Table2.
I ve done that with this code, but i dont know how to join the tables:
SELECT [ColumnFromTable3],
CASE
WHEN [ColumnFromTable3] IN ('0001', '7004', '1004', '7001', '8001', '7014', '7012', '7015', '7006') THEN 'R1'
WHEN [ColumnFromTable3] IN ('9001', '9017') THEN 'R2'
WHEN [ColumnFromTable3] IN ('9003', '9006') THEN 'R3'
WHEN [ColumnFromTable3] IN ('9005', '9008', '9004') THEN 'R4'
ELSE 'OTHER'
END AS [NewColumn3]
FROM [dbo].[Table3]
The problem is that Table3 is not related with any other table and i need one column from that table.
Can you please suggest me how can i solve this. Thank you
Generally, there are several ways to join tables it depends on result which You expect, please check following What's the difference between INNER JOIN, LEFT JOIN, RIGHT JOIN and FULL JOIN?
example of right JOIN from my program :
string sqlCheck = #"SELECT e.GBC, e.Replaced, e.Description, Barcode, Location, Quantity, Buildneed, p.Quantity - e.Buildneed as Afterbuild FROM Parts p Right JOIN Excel e ON e.GBC = p.GBC";
one method you can use row_number() and use left join
with cte as
(
select row_number() over(order by col) rn
from table1
),cte1 as
(
SELECT [ColumnFromTable3],row_number() over(order by col) rn1,
CASE
WHEN [ColumnFromTable3] IN ('0001', '7004', '1004', '7001', '8001', '7014', '7012', '7015', '7006') THEN 'R1'
WHEN [ColumnFromTable3] IN ('9001', '9017') THEN 'R2'
WHEN [ColumnFromTable3] IN ('9003', '9006') THEN 'R3'
WHEN [ColumnFromTable3] IN ('9005', '9008', '9004') THEN 'R4'
ELSE 'OTHER'
END AS [NewColumn3]
FROM [dbo].[Table3]
) select cte.*,cte1* from cte left join cte1 on cte.rn=cte1.rn1

Change existing sql to left join only on first match

Adding back some original info for historical purposes as I thought simplifying would help but it didn't. We have this stored procedure, in this part it is selecting records from table A (calldetail_reporting_agents) and doing a left join on table B (Intx_Participant). Apparently there are duplicate rows in table B being pulled that we DON'T want. Is there any easy way to change this up to only pick the first match on table B? Or will I need to rewrite the whole thing?
SELECT 'Agent Calls' AS CallType,
CallDate,
CallTime,
RemoteNumber,
DialedNumber,
RemoteName,
LocalUserId,
CallDurationSeconds,
Answered,
AnswerSpeed,
InvalidCall,
Intx_Participant.Duration
FROM calldetail_reporting_agents
LEFT JOIN Intx_Participant ON calldetail_reporting_agents.CallID = Intx_Participant.CallIDKey
WHERE DialedNumber IN ( SELECT DialedNumber
FROM #DialedNumbers )
AND ConnectedDate BETWEEN #LocStartDate AND #LocEndDate
AND (#LocQueue IS NULL OR AssignedWorkGroup = #LocQueue)
Simpler version: how to change below to select only first matching row from table B:
SELECT columnA, columnB FROM TableA LEFT JOIN TableB ON someColumn
I changed to this per the first answer and all data seems to look exactly as expected now. Thank you to everyone for the quick and attentive help.
SELECT 'Agent Calls' AS CallType,
CallDate,
CallTime,
RemoteNumber,
DialedNumber,
RemoteName,
LocalUserId,
CallDurationSeconds,
Answered,
AnswerSpeed,
InvalidCall,
Intx_Participant.Duration
FROM calldetail_reporting_agents
OUTER APPLY (SELECT TOP 1
*
FROM Intx_Participant ip
WHERE calldetail_reporting_agents.CallID = ip.CallIDKey
AND calldetail_reporting_agents.RemoteNumber = ip.ConnValue
AND ip.HowEnded = '9'
AND ip.Recorded = '0'
AND ip.Duration > 0
AND ip.Role = '1') Intx_Participant
WHERE DialedNumber IN ( SELECT DialedNumber
FROM #DialedNumbers )
AND ConnectedDate BETWEEN #LocStartDate AND #LocEndDate
AND (#LocQueue IS NULL OR AssignedWorkGroup = #LocQueue)
You can try to OUTER APPLY a subquery getting only one matching row.
...
FROM calldetail_reporting_agents
OUTER APPLY (SELECT TOP 1
*
FROM intx_Participant ip
WHERE ip.callidkey = calldetail_reporting_agents.callid) intx_participant
WHERE ...
You should add an ORDER BY in the subquery. Otherwise it isn't deterministic which row is taken as the first. Or maybe that's not an issue.

How to join two tables having two common column values and unioning the rest

I'd like to combine Table A and Table B at the link below and end up with Table C. What is the best way to do this in SQL? I've thought about creating a composite key between the tables for LedgerID + Year doing an inner join and then unioning the left and right only data. I'm also curious how to avoid duplicating values across rows like Balance = 50.00 ending up in rows for Tires and Windshield.
Try a full outer join, joining on LedgerID and Year, using coalesce to show Table B's LedgerID/Year when Table A's is NULL:
SELECT
COALESCE(A.LedgerID, B.LedgerID) as LedgerID,
COALESCE(A.Year, B.Year) as Year,
A.Title,
A.Payment,
B.Balance
FROM "Table A" AS A
FULL OUTER JOIN "Table B" AS B ON (A.LedgerID=B.LedgerID AND A.Year=B.Year)
--Please try this Query. Since you have only reference LedgerId and Year, the balance will show 50 for both Tires & Windshield
; with cte_Ledger (LedgerId, [year])
AS
(
Select DISTINCT LedgerId, [year]
From tableA
UNION
Select DISTINCT LedgerId, [year]
From tableB
)
select t.LedgerId
, t.[year]
, t1.Title
, T1.Payments
, t2.Balance
FROM cte_Ledger t
left join tableA t1 on t.LedgerId = t1.LedgerId and t.[year] = t1.[year]
left join tableB t2 on t2.LedgerId = t.LedgerId and t2.[year] = t.[year]
I think so, Above Queries will not help to get expected result.
some misunderstanding is with requirement.
For ledgerid = 22 and Year = 2017, have 2 records in table-A and 1 with Table-B. But in expecting result, Balance 50(Record of table-B) is exists with matched first row of Table-A only. As per above all logic it will be with 2 Records where ledgerid = 22, Year = 2017 and Title with "Tires" & "Windshield".
If required same result as mentioned then need to use recursive CTE or ranking function with order of ID column.
Here is my solution after I loaded the tables, another nested case statement may be need to format out the zero on Ledger 24.
Select
[LedgerID],
[Year],
Case when PayRank = 1 then Title else '' end as Title,
Case when PayRank = 1 then convert(varchar(20),Payments) else '' end as
Payments,
Case when BalRank = 1 then convert(varchar(20),Balance) else '' end as
Balance
from(
SELECT
B.[LedgerID]
,B.[Year]
,Rank()Over(Partition by B.LedgerID,Payments order by
B.LedgerID,B.Year,Title) as PayRank
,isnull([Title],'') as Title
,isnull([Payments],0) as Payments
,Rank()Over(Partition by B.LedgerID,B.Year order by
B.LedgerID,B.Year,Payments) as BalRank
,Balance
FROM [TableB] B
left outer join [TableA] A
on A.LedgerID = B.LedgerID
) Query
order by LedgerID,Year

How to do a join in Oracle tables?

I am trying to help a co-worker do an inner join on two oracle tables so he can build a particular graph on a report.
I have no Oracle experience, only SQL Server and have gotten to what seems like the appropriate statement, but does not work.
SELECT concat(concat(month("a.timestamp"),','),day("a.timestamp")) as monthDay
, min("a.data_value") as minTemp
, max("a.data_value") as maxTemp
, "b.forecast" as forecastTemp
, "a.timestamp" as date
FROM table1 a
WHERE "a.category" = 'temperature'
GROUP BY concat(concat(month("timestamp"),','),day("timestamp"))
INNER JOIN (SELECT "forecast"
, "timestamp"
FROM table2
WHERE "category" = 'temperature') b
ON "a.timestamp" = "b.timestamp"
It doesn't like my aliases for some reason. It doesn't like not having quotes for some reason.
Also when I use the fully scored names it still fails because:
ORA-00933 SQL command not properly ended
The order of the query should be
SELECT
FROM
INNER JOIN
WHERE
GROUP BY
as below
SELECT concat(concat(month("a.timestamp"),','),day("a.timestamp")) as monthDay
, min("a.data_value") as minTemp
, max("a.data_value") as maxTemp
, "b.forecast" as forecastTemp
, "a.timestamp" as date
FROM table1 a
INNER JOIN (SELECT "forecast"
, "timestamp"
FROM table2
WHERE "category" = 'temperature') b
ON "a.timestamp" = "b.timestamp"
WHERE "category" = 'temperature'
GROUP BY concat(concat(month("timestamp"),','),day("timestamp"))
In a flood of attempts, here's yet another one.
table2 can be moved out of subquery; join it with table1 on category as well
note that all non-aggregates columns (from the SELECT) have to be contained in the GROUP BY clause. It seems that a.timestamp contains more info than just month and day - if that's so, it'll probably ruin the whole result set as data won't be grouped by monthday, but by the whole date - consider removing it from SELECT, if necessary
SELECT TO_CHAR(a.timestamp,'mm.dd') monthday,
MIN(a.data_value) mintemp,
MAX(a.data_value) maxtemp,
b.forecast forecasttemp,
a.timestamp c_date
FROM table1 a
JOIN table2 b ON a.timestamp = b.timestamp
AND a.category = b.category
WHERE a.category = 'temperature'
GROUP BY TO_CHAR(a.timestamp,'mm.dd'),
b.forecast,
a.timestamp;
The correct (simplified) syntax of select is
SELECT <columns>
FROM table1 <alias>
JOIN table2 <alias> <join_condition>
WHERE <condition>
GROUP BY <group by columns>
You are doing it wrong. Use subquery:
SELECT c.*, b.`forecast` as forecastTemp
FROM
(SELECT concat(concat(month(a.`timestamp`),','),day(a.`timestamp`)) as monthDay
, min(a.`data_value`) as minTemp
, max(a.`data_value`) as maxTemp
, a.`timestamp` as date
FROM table1 a
WHERE `category`='temperature'
GROUP BY concat(concat(month(`timestamp`),','),day(`timestamp`))) c
INNER JOIN (SELECT `forecast`
, `timestamp`
FROM table2
WHERE `category` = 'temperature') b
ON c.`timestamp` = b.`timestamp`;
In addition to the order of the components other answers have mentioned (where goes after join etc), you also need to remove all of the double-quote characters. In Oracle, these override the standard naming rules, so "a.category" is only valid if your table actually has a column named, literally, "a.category", e.g.
create table demo ("a.category" varchar2(10));
insert into demo ("a.category") values ('Weird');
select d."a.category" from demo d;
It's quite rare to need to do this.
The query should look something like this:
SELECT to_char(a.timestamp, 'MM-DD') as monthDay,
min(a.data_value) as minTemp,
max(a.data_value) as maxTemp,
b.forecast as forecastTemp
FROM table1 a JOIN
table2 b
ON a.timestamp = b.timestamp and b.category = 'temperature'
WHERE a.category = 'temperature'
GROUP BY to_char(timestamp, 'MM-DD'), b.forecast;
I'm not 100% sure this is what you want. Your query has numerous issues and complexities:
You don't need a subquery in the FROM clause.
You can use to_char() instead of the more complex date string processing.
The group by did not contain all the relevant fields.
Don't use double quotes, unless really, really needed.

Creating a view in SQL with a case statement in the select

I know something must be wrong with my syntax but I can't seem to figure it out.
I want to populate this column prop_and_cas_dtl_prdct_desc from either expir_prop_and_cas_dtl_prdct_cd or ren_prop_and_cas_dtl_prdct_cd depending on the value in type_indicator but before it goes into prop_and_cas_dtl_prdct_desc it should look up the prop_and_cas_dtl_prdct_desc from pc_ref_detail_product_cd and select the one corresponding to its expir_prop_and_cas_dtl_prdct_cd or ren_prop_and_cas_dtl_prdct_cd.
I apologize for the terrible indenting, I know it is difficult to read but this is the best way I know how to put it.
select
,ren_prop_and_cas_dtl_prdct_cd
...
,p_and_c_cd
,case when type_indicator in ('R','C') then
select prop_and_cas_dtl_prdct_desc
from pc_ref_detail_product_cd a inner join op_pif_coverage_rpc_new b
on a.prop_and_cas_dtl_prdct_cd = b.expir_prop_and_cas_dtl_prdct_cd
else when type_indicator in ('N','O') then
select prop_and_cas_dtl_prdct_desc
from pc_ref_detail_product_cd a inner join op_pif_coverage_rpc_new b
on a.prop_and_cas_dtl_prdct_cd = b.ren_prop_and_cas_dtl_prdct_cd
else NULL
END
AS prop_and_cas_dtl_prdct_desc
FROM dbo.op_pif_coverage_rpc_new
Here is the code I used to create my reference table
create table pc_ref_detail_product_cd(
prop_and_cas_dtl_prdct_cd char(2),
prop_and_cas_dtl_prdct_desc char(30)
)
insert into pc_ref_detail_product_cd (prop_and_cas_dtl_prdct_cd, prop_and_cas_dtl_prdct_desc)
values ('01', 'CORE'),
('02', 'FORECLOSED'),
('04', 'TRUST'),
('06', 'MORTGAGE HOLDERS E&O'),
('07', 'SECURITY INTEREST E&O')
If you need to select column from different table depending on value in additional column you need to include all tables in query, with appropriate JOIN and than use case statement like so
SELECT CASE WHEN a.MyColumn = 0 THEN b.SomeColumn
WHEN a.MyColumn = 1 THEN a.SomeColumn
END AS SomeColumn
FROM MyTableA AS a
JOIN MyTableB AS b
ON a.ID = b.ID
Instead of select statement in case statement, you just going to select column from ether table that you need for each particular case.
I got it figured out. Here is the SQL I used. Sorry if it wasn't apparent what I wanted to do from my horrible code in the original question.
select
,ren_prop_and_cas_dtl_prdct_cd
...
,p_and_c_cd
,case when type_indicator in ('R','C') then
(select prop_and_cas_dtl_prdct_desc
from pc_ref_detail_product_cd a where expir_prop_and_cas_dtl_prdct_cd = prop_and_cas_dtl_prdct_cd)
when type_indicator in ('N','O') then
(select prop_and_cas_dtl_prdct_desc
prop_and_cas_dtl_prdct_desc
from pc_ref_detail_product_cd a where ren_prop_and_cas_dtl_prdct_cd = prop_and_cas_dtl_prdct_cd)
else NULL
END
AS prop_and_cas_dtl_prdct_desc
FROM dbo.op_pif_coverage_rpc_new