Writing a query - sql

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

Related

Oracle SQL Developer - error when referencing fields within nested from statements

For the below query I am getting an error with line 4 when referencing variables within "y". The query runs successfully when I use just " y.* " (line 5), however it generates an error when I try to also pull from the specified fields in line 4 (y.field1 as PRODUCT, y.field2 as PRODUCT_TYPE, y.entity, y.TYPE1). For the output, I want these fields listed first for visual reference.
I have this approach/ logic working for other queries (as i'm re using this logic for multiple variations of queries and various tables). However, I think that the issue with this one lies in my attempt to reference fields from tables that are in my join statements.
(
select
-- categorization fields:
-- table2.field1 as PRODUCT, table2.field2 as PRODUCT_TYPE, table3.entity, table3.TYPE1
y.field1 as PRODUCT,
y.field2 as PRODUCT_TYPE,
y.entity,
y.TYPE1
,y.*
from (
select *
from (
-- table references:
select table1.*,
row_number() over (
partition by
-- categorization fields:
table2.field1,
table2.field2,
table3.entity,
table3.TYPE1
order by table3.entity
) as rn
-- table references
from table1
-- joins, links, and filtering:
inner join table6 on table1.field_1 = table6.code1
inner join table5 on (table6.code = table5.code1)
AND (table6.code = table5.code)
left join table3 on table6.ent1 = table3.ent_code
left join table2 on table1.extid = table2.extID
where table1.tdate between '01-APR-19' and '01-APR-21'
AND table1.refe NOT IN ('OFF')
) x
-- sample rows:
where rn <= 2
) y
);
Let me know if anyone has a way that I can maybe better specify which tables those fields come from. I wish I could just do something like this:
y.table2.field1 as PRODUCT,
y.table2.field2 as PRODUCT_TYPE,
y.table3.entity,
y.table3.TYPE1
Sorry that I don't have a fiddle available!
Let me know if anyone has a way that I can maybe better specify which tables those fields come from.
Don't use select *. Instead, use the column names and give them appropriate aliases so you know where they came from:
As an example:
SELECT small_value,
medium_value,
big_value
FROM (
SELECT small.value AS small_value,
medium.value AS medium_value,
big.value AS big_value
FROM big
CROSS JOIN medium
CROSS JOIN small
)
WHERE 1 = 1
In your query, instead of using SELECT * in y or using SELECT table1.* in x you can name the columns and give them descriptive aliases.
I am getting an error with line 4 when referencing variables within "y".
(
select
-- categorization fields:
-- table2.field1 as PRODUCT, table2.field2 as PRODUCT_TYPE, table3.entity, table3.TYPE1
That is because you cannot see TABLE2 or TABLE3 because the only "view" you are looking at is of the sub-query with the alias y.
If you want to see those columns then you need to SELECT them inside the x subquery and pass them to each subsequent outer-query.
(
select *
from (
-- table references:
select table1.field1 AS t1_product,
table1.field2 AS t1_product_type,
table1.entity AS t1_entity,
table1.type1 AS t1_type1,
table2.field1 AS t2_product,
table2.field2 AS t2_product_type,
table2.entity AS t2_entity,
table2.type1 AS t2_type1,
table3.field1 AS t3_product,
table3.field2 AS t3_product_type,
table3.entity AS t3_entity,
table3.type1 AS t3_type1,
row_number() over (
partition by
-- categorization fields:
table2.field1,
table2.field2,
table3.entity,
table3.TYPE1
order by table3.entity
) as rn
-- table references
from table1
-- joins, links, and filtering:
inner join table6 on table1.field_1 = table6.code1
inner join table5 on (table6.code = table5.code1)
AND (table6.code = table5.code)
left join table3 on table6.ent1 = table3.ent_code
left join table2 on table1.extid = table2.extID
where table1.tdate between '01-APR-19' and '01-APR-21'
AND table1.refe NOT IN ('OFF')
) x
-- sample rows:
where rn <= 2
);

Query result not working with array type in PostgreSQL

I have two tables which contains a column with data type array in PostgreSQL. The structure is like below:
tbl_tour_packages
tbl_header_images
I have a query which contains several joins. The query is working fine with other joins and showing no error. But missing the values from tbl_header_images.
The query is:
SELECT
t1.tour_id AS pid,
t1.tour_name AS title,
t1.tour_duration AS nights,
t1.tour_price_full AS price,
t1.discount AS discount,
t1.tour_seo_title AS seo,
t3.category AS category,
t4.image_names[1] AS image_url,
CASE WHEN max(s.state_name) IS NULL THEN NULL ELSE array_agg(s.state_name) END AS state,
CASE WHEN max(o.destination) IS NULL THEN NULL ELSE array_agg(o.destination) END AS destinations
FROM tbl_tour_packages t1
LEFT JOIN tbl_countries t2 ON t1.tour_country_iso = t2.iso
LEFT JOIN tbl_categories t3 on t1.tour_category_id = t3.id
LEFT JOIN tbl_header_images t4 ON t1.tour_id = t4.package_id
LEFT JOIN tbl_states AS s ON (t1.tour_state #> array[s.state_code])
LEFT JOIN tbl_destinations AS o ON (t1.tour_destination #> array[o.id])
WHERE t1.tour_status = 1
GROUP BY 1,7,8
ORDER BY view_count ASC LIMIT 6
I want to get the 'image_name' from tbl_header_images. Any quick help or suggestion will be appreciated.
before WHERE clause you should be able to do something like:
, unnest(image_names) _image_names
and then in select statement aggregate that back into an array
array_agg(_image_names) AS image_names
I don't quite get the t4.image_names[1] AS image_url attempt, but I'm sure you can pick it up from here.
so the whole query would be something like:
edit: I've stripped extra groupping
SELECT
t1.tour_id AS pid,
t1.tour_name AS title,
t1.tour_duration AS nights,
t1.tour_price_full AS price,
t1.discount AS discount,
t1.tour_seo_title AS seo,
t3.category AS category,
(array_agg(_image_names))[1] AS image_url,
CASE WHEN max(s.state_name) IS NULL THEN NULL ELSE array_agg(s.state_name) END AS state,
CASE WHEN max(o.destination) IS NULL THEN NULL ELSE array_agg(o.destination) END AS destinations
FROM tbl_tour_packages t1
LEFT JOIN tbl_countries t2 ON t1.tour_country_iso = t2.iso
LEFT JOIN tbl_categories t3 on t1.tour_category_id = t3.id
LEFT JOIN tbl_header_images t4 ON t1.tour_id = t4.package_id
LEFT JOIN tbl_states AS s ON (t1.tour_state #> array[s.state_code])
LEFT JOIN tbl_destinations AS o ON (t1.tour_destination #> array[o.id])
, unnest(t4.image_names) AS _image_names
WHERE t1.tour_status = 1
GROUP BY 1,7
ORDER BY view_count ASC LIMIT 6
alternatively I'd go with subselect:
SELECT t1.*,
(SELECT image_names[1] FROM tbl_header_images WHERE package_id = t1.tour_id) AS image_url
FROM t1, t2, t3
WHERE ...

(probably) very simple SQL query needed

Having a slow day....could use some assistance writing a simple ANSI SQL query.
I have a list of individuals within families (first and last names), and a second table which lists a subset of those individuals. I would like to create a third table which flags every individual within a family if ANY of the individuals are not listed in the second table. The goal is essentially to flag "incomplete" families.
Below is an example of the two input tables, and the desired third table.
As I said...very simple...having a slow day. Thanks!
I think you want a left join and case expression:
select t1.*,
(case when t2.first_name is null then 'INCOMPLETE' else 'OK' end) as flag
from table1 t1 left join
table2 t2
on t1.first_name = t2.first_name and t1.last_name = t2.last_name;
Of course, this marks "Diane Thomson" as "OK", but I think that is an error in the question.
EDIT:
Oh, I see. The last name defines the family (that seems like a pretty big assumption). But you can do this with window functions:
select t1.*,
(case when count(t2.first_name) over (partition by t1.last_name) =
count(*) over (partition by t1.last_name)
then 'OK'
else 'INCOMPLETE'
end) as flag
from table1 t1 left join
table2 t2
on t1.first_name = t2.first_name and t1.last_name = t2.last_name;
That's not simple, at least not in SAS :-)
Standard SQL, when Windowed Aggregates are supported:
select ft.*,
-- counts differ when st.first_name is null due to the outer join
case when count(*) over (partition by ft.last_name)
= count(st.first_name) over (partition by ft.last_name)
then 'OK'
else 'INCOMPLETE'
end
from first_table as ft
left join second_table as st
on ft.first_name = st.first_name
and ft.last_name = ft.last_name
Otherwise you need to a standard aggregate and join back:
select ft.*, st.flag
from first_table as ft
join
(
select ft.last_name,
case when count(*)
= count(st.first_name)
then 'OK'
else 'INCOMPLETE'
end as flag
from first_table as ft
left join second_table as st
on ft.first_name = st.first_name
and ft.last_name = st.last_name
group by ft.last_name
) as st
on ft.last_name = st.last_name
It is pretty easy to do in SAS if you want to take advantage of its non-ANSI SQL feature of automatically re-merging aggregate function results back onto detail records.
select
a.first
, a.last
, case when 1=max(missing(b.last)) then 'INCOMPLETE'
else 'OK'
end as flag
from table1 a left join table2 b
on a.last=b.last and a.first=b.first
group by 2
order by 2,1
;

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

Using UNION in SQL with queries and subqueries

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')