Trying to join two tables via subquery - sql

Current query below
select
x.OVERALL_ID,
extract(year from y.tsdate) as year,
extract(month from y.tsdate) as month,
round(sum(y.grossamount),2) as "labour cost",
sum(y.reg)+sum(y.ot) as "labour hours"
from
(
select OVERALL_ID,
BOAT_NAME
from TV_VESSEL_VISIT
group by OVERALL_ID,VESSEL_NAME
order by OVERALL_ID, VESSEL_NAME
) as x
inner join
(
select *
from TRANS
where ratedesc = 'Labour'
and opsdesc = 'Ops'
and ACTDESC = 'Nature of Job'
and terminal = 'UKN'
and reconciled = 'Y'
and TSDATE between '20-JAN-01' and '20-JAN-31'
) as y on x.BOAT_NAME = y.BOATNAME
group by OVERALL_ID, extract(year from tsdate), extract(month from tsdate)
order by OVERALL_ID, extract(year from tsdate), extract(month from tsdate);
Desired result is OVERALL_ID's labour cost/hours grouped into year and month
Currently getting the below error
ORA-00933: SQL command not properly ended
00933. 00000 - "SQL command not properly ended"
*Cause:
*Action:
Error at Line: 14 Column: 3
Trying to follow this link https://www.geeksengine.com/database/subquery/subquery-in-join-operation.php

Orable allows AS when declaring a column alias, but does not allow it for a table alias. The subquery alias is the same case as table alias. try ) x instead of ) as x, and the same thing for y. This is one of the syntax errors that causes ORA-00933.

If using subqueries DO NOT use ORDER BY inside those subqueries. There is no good purpose to the ordering, it just isn't required.
Try this:
SELECT
x.OVERALL_ID
, extract(year FROM y.tsdate) AS year
, extract(month FROM y.tsdate) AS month
, round(sum(y.grossamount), 2) AS "labour cost"
, sum(y.reg) + sum(y.ot) AS "labour hours"
FROM (
SELECT DISTINCT
OVERALL_ID
, BOAT_NAME
FROM TV_VESSEL_VISIT
) x
INNER JOIN (
SELECT *
FROM TRANS
WHERE ratedesc = 'Labour'
AND opsdesc = 'Ops'
AND ACTDESC = 'Nature of Job'
AND terminal = 'UKN'
AND reconciled = 'Y'
AND TSDATE >= to_date('2020-01-01','yyy-mm-dd') AND TSDATE < to_date('2020-02-01','yyyy-mm-dd')
) y ON x.BOAT_NAME = y.BOATNAME
GROUP BY
OVERALL_ID
, extract(year FROM tsdate)
, extract(month FROM tsdate)
ORDER BY
OVERALL_ID
, extract(year FROM tsdate)
, extract(month FROM tsdate)
;
Notes: I have removed the unwanted ORDER BY in the upper subquery, and changed this to use SELECT DISTINCT (it will produce the same result as the previous group by subquery). Also I have changed the syntax used for the date range. Please avoid using 2 digit year references, always use the full year. Additionally I always recommend avoiding the use of between for date ranges it is far more predictable to use the combination of >= with < as you see above. Plus I have used to_date() so it is clear what dates I am using for the date range - which will give you every row of data relevant to January 2020.
The previous between syntax could possibly miss a whole day's data

Related

BigQuery DATEADD(MAX(myDate), 1, YEAR) return Function not found: DATEADD; Did you mean date_add? at [6:7]

I'm trying to find a date, then add a column with that date +1 year. But for some reason I can't use an aggregate function inside the DATEADD method. Does anyone have a workaround for this?
The console returns this error.
Function not found: DATEADD; Did you mean date_add? at [6:7]
Here is the query.
SELECT d.org_id,
o.name,
SUM(CAST(d.converted_value AS NUMERIC)) as ltv,
MIN(won_time) AS first_deal_date,
MAX(won_time) AS last_deal_date,
DATEADD(MAX(won_time), 1, YEAR) AS churn_date,
EXTRACT(YEAR FROM MAX(won_time)) < EXTRACT(YEAR FROM CURRENT_DATE) as churn
FROM deals d
INNER JOIN organizations AS o ON d.org_id = o.id
WHERE d.status = 'won'
GROUP BY d.org_id, o.name;
Are you looking for this?
DATE_ADD(MAX(won_time), INTERVAL 1 YEAR) AS churn_date,
This assumes that won_time is a date. If not, either convert it to a date or use DATETIME_ADD() or TIMESTAMP_ADD().

Invalid identifier in pivot table

Here is my query:
SELECT NVL(REVENUE,0), OUTNO, MONTH_NAME FROM
(
SELECT ROUND((RETURNDATE-STARTDATE)*DAILYRATE) AS REVENUE,
OUTNO,
EXTRACT(MONTH FROM RETURNDATE)AS MONTH_NAME
FROM RAGREEMENT LEFT JOIN VEHICLE ON
RAGREEMENT.LICENSENO=VEHICLE.LICENSENO
AND EXTRACT(YEAR FROM RETURNDATE)=EXTRACT(YEAR FROM SYSDATE)-1
)
PIVOT (
SUM(REVENUE)
FOR OUTNO IN (1,2,3,4,5,6,-1 AS TOTAL)
)
ORDER BY MONTH_NAME;
and here is the error
SELECT NVL(REVENUE,0), OUTNO, MONTH_NAME FROM
*
ERROR at line 1:
ORA-00904: "OUTNO": invalid identifier
I fail to understand why this happens when SELECT * works perfectly
What comes out from a pivot is a whole new set of columns names, and for each one of those new columns, you will need an NVL() or COALESCE(). This is because a completely new "matrix" is formed and many positions in this can be null. You cannot overcome this by using NVL() in the inner subquery.
Assuming you want months as columns your query might look more like this:
SELECT
OUTNO
, NVL('M1', 0)
, NVL('M2', 0)
, NVL('M3', 0)
, NVL('M4', 0)
, NVL('M5', 0)
, NVL('M6', 0)
, NVL('M7', 0)
, NVL('M8', 0)
, NVL('M9', 0)
, NVL('M10', 0)
, NVL('M11', 0)
, NVL('M12', 0)
FROM (
SELECT
ROUND((RETURNDATE - STARTDATE) * DAILYRATE) AS REVENUE
, OUTNO
, 'M' || EXTRACT(MONTH FROM RETURNDATE) AS MONTH_NAME
FROM RAGREEMENT
LEFT JOIN VEHICLE ON RAGREEMENT.LICENSENO = VEHICLE.LICENSENO
AND EXTRACT(YEAR FROM RETURNDATE) = EXTRACT(YEAR FROM SYSDATE) - 1
)
PIVOT(
SUM(REVENUE)
FOR MONTH_NAME IN ('M1','M2','M3','M4','M5','M6','M7','M8','M9','M10','M11','M12')
)
ORDER BY OUTNO;
This line produces the new columns:
FOR MONTH_NAME IN ('M1','M2','M3','M4','M5','M6','M7','M8','M9','M10','M11','M12')
and it is each one of these you will need to "fix" for nulls in the select clause.
To put OUTNO values into columns requires a similar pattern but you need to know what the distinct set of values will be from that originating column. This MIGHT be 1,2,3,4,5,6,-1 but I wasn't certain.
nb: I prefixed 'M' in columns headings as many systems object to numbers as heading names.

Not Exists query

I'm trying to find the clients, those who didn't order in the last 2 years and they ordered this year more than 500.. I wrote this query and I used the "NOT EXISTS" condition, but it is still showing me the wrong results.
Some suggestions would be appreciated.
My code:
SELECT
"Sales"."Kundennummer" as 'Neuer Kunde',
year("Sales"."Datum"),
sum("Sales"."Umsatz mit Steuer") as "Umsatz"
FROM "Sales"
WHERE year("Sales"."Datum") = '2017'
AND NOT EXISTS
(
SELECT "Sales"."Kundennummer"
FROM "Sales"
WHERE year("Sales"."Datum") = '2015'
AND year("Sales"."Datum") = '2016'
)
GROUP BY
"Sales"."Kundennummer",
"Sales"."Datum"
HAVING sum("Sales"."Umsatz mit Steuer") > 500
The query in the NOT EXISTS clause will probably yield 0 rows, since a row can't have Datum both 2015 and 2016. So it should probably be OR instead of AND.
Also, if you fix this, there is no link between the subquery and the superquery, which means that it will return rows for any customer (given that there exists a row with Datum either 2015 or 2016 in your table which I guess it does).
So, something like:
SELECT
"Sales"."Kundennummer" as 'Neuer Kunde',
year("Sales"."Datum"),
sum("Sales"."Umsatz mit Steuer") as "Umsatz"
FROM "Sales" sales
WHERE year("Sales"."Datum") = '2017'
AND NOT EXISTS
(
SELECT "Sales"."Kundennummer"
FROM "Sales" salesI
WHERE salesI."Kundennummer" = sales."Kundennummer"
AND (year("Sales"."Datum") = '2015'
OR year("Sales"."Datum") = '2016')
)
GROUP BY
"Sales"."Kundennummer",
"Sales"."Datum"
HAVING sum("Sales"."Umsatz mit Steuer") > 500
Your EXISTS query is not correlated to the main query, i.e. it doesn't look for data for the Kundennummer in question, but whether there are any records in 2015 and 2016.
(You also have the condition for the years wrong by using AND where it must be OR and you should not use quotes on numbers like 2015', and you should not use single quotes on names like 'Neuer Kunde'.)
It should be
AND NOT EXISTS
(
SELECT *
FROM Sales other_years
WHERE other_years.Kundennummer = Sales.Kundennummer
AND year(other_years.Datum) in (2015, 2016)
)
or uncorrelated with NOT IN
AND Kundennummer NOT IN
(
SELECT Kundennummer
FROM Sales
WHERE year(Datum) in (2015, 2016)
)
Be aware though, that when using NOT IN the subquery must return no nulls. E.g. where 3 not in (1, 2, null) does not result in true, as one might expect, because the DBMS argues that the unknown value (null) might very well be a 3 :-)
I propose you here below 3 different ways to do it:
Joining 2 tables
select this_year_sales.kundenummer, this_year_sales.tot_umsatz
from (select sum(umsatz) tot_umsatz, kundenummer from sales where extract(year from (datum)) = extract(year from sysdate) group by kundenummer) this_year_sales
, (select kundenummer, max(datum) max_datum from sales where datum < trunc(sysdate, 'year') group by kundenummer) previous_sales
where this_year_sales.kundenummer = previous_sales.kundenummer
and extract(year from previous_sales.max_datum) < (extract(year from sysdate)-2)
and this_year_sales.tot_umsatz > 500;
Using NOT INT
select kundenummer, sum(umsatz)
from sales s
where extract(year from datum) = extract(year from sysdate)
and kundenummer not in (select kundenummer from sales where extract(year from datum) > (extract(year from sysdate) - 2) and extract(year from datum) < (extract(year from sysdate)-1))
group by kundenummer
having sum(umsatz) > 500;
Using NOT EXISTS
select kundenummer, sum(umsatz)
from sales s
where extract(year from datum) = extract(year from sysdate)
and not exists(
select s1.kundenummer, s1.datum from sales s1 where extract (year from s1.datum) >= (extract(year from sysdate)-2) and extract(year from s1.datum) < extract (year from sysdate) and s1.kundenummer = s.kundenummer
)
group by kundenummer
having sum(umsatz) > 500;

Refer to a Derived Table in a SELECT Subquery

In the code below, the resulting error is "object t does not exist". T is the derived table defined in FROM. Rather than refiltering in the SELECT subquery, I would like to use the derived table to save on processing. Since FROM is processed first in the order of operations, I feel that there should be a way for me to refer to "t" in the SELECT.
(I am in Teradata in case that matters)
SELECT (100000/(SELECT COUNT(DISTINCT EXTRACT(DAY FROM t.saledate))
FROM t
WHERE EXTRACT(MONTH FROM t.saledate) = 11)) as "NOVEMBER"
FROM (SELECT sprice, quantity, sku, store, saledate
FROM trnsact
WHERE (saledate BETWEEN '2004-11-01' AND '2004-12-31')
) as t
We can achieve the result (it seems like you are going for) with an inline view, or a common table expression. As an example of a using an inline view:
SELECT ( 100000
/ COUNT(DISTINCT
CASE WHEN EXTRACT(MONTH FROM t.saledate) = 11
THEN EXTRACT(DAY FROM t.saledate)
ELSE NULL
END
)
) AS "NOVEMBER"
FROM ( SELECT r.sprice
, r.quantity
, r.sku
, r.store
, r.saledate
FROM trnsact r
WHERE r.saledate BETWEEN '2004-11-01' AND '2004-12-31'
) t
I'd also want to avoid any potential "divide by zero" error, so I'd wrap that COUNT() expression in a NULLIFZERO function.
We will note that for that resultset, we wouldn't actually need an inline view or CTE. It could be achieved with a much simpler query:
SELECT ( 100000
/ NULLIFZERO(COUNT(DISTINCT EXTRACT(DAY FROM t.saledate)))
) AS "NOVEMBER"
FROM trnsact t
WHERE t.saledate >= '2004-11-01'
AND t.saledate < '2004-12-01'
If you're using SQL Server you'd do:
;WITH t as
SELECT sprice, quantity, sku, store, saledate
FROM trnsact
WHERE (saledate BETWEEN '2004-11-01' AND '2004-12-31')
SELECT (100000/(SELECT COUNT(DISTINCT EXTRACT(DAY FROM t.saledate))
FROM t
WHERE EXTRACT(MONTH FROM t.saledate) = 11)) as "NOVEMBER"
I think there are a lot more improvements that can be made to the query, but this is a good start.

Joining multiple sum sql statements

How can I join multiple sql statements. I need to display in one view respectively 2004,2008,2009 and so on
SELECT SUM(ACQUISITIONPRICE) AS YEAR_2007
FROM TRANS
WHERE DATEACQUIRED LIKE '%07';
SELECT SUM(ACQUISITIONPRICE) AS YEAR_2008
FROM TRANS
WHERE DATEACQUIRED LIKE '%08';
SELECT SUM(ACQUISITIONPRICE) AS YEAR_2009
FROM TRANS
WHERE DATEACQUIRED LIKE '%09';
check this sql fiddle
I have handled your requirement with case statement which seems to be very easy.
SELECT SUM(ACQUISITIONPRICE) AS TOTALPRICE
, EXTRACT(year from DATEACQUIRED) AS YEAR
FROM TRANS
GROUP BY EXTRACT(year from DATEACQUIRED)
ORDER BY YEAR;
SELECT Sum(CASE
WHEN Extract(year FROM dateacquired) = 2007 THEN acquisitionprice
ELSE 0
END) AS YEAR_2007,
Sum(CASE
WHEN Extract(year FROM dateacquired) = 2008 THEN acquisitionprice
ELSE 0
END) AS YEAR_2008,
Sum(CASE
WHEN Extract(year FROM dateacquired) = 2009 THEN acquisitionprice
ELSE 0
END) AS YEAR_2009
FROM trans
Just use GROUP BY like so:
SELECT SUM(ACQUISITIONPRICE) AS TOTALPRICE
, EXTRACT(year from DATEACQUIRED) AS YEAR
FROM TRANS
GROUP BY EXTRACT(year from DATEACQUIRED)
ORDER BY YEAR
If you really want to "join" them all in one row, with specific column names, you can do the following (though this approach is less flexible, since the query will have to be manually modified every year). Also note that although the question specifically mentioned "joining" the results, the join as shown below is completely unnecessary. Each column could simply be part of the select clause without any join. (here is the SqlFiddle)
SELECT * FROM
(SELECT SUM(ACQUISITIONPRICE) AS YEAR_2007
FROM TRANS
WHERE EXTRACT(year from DATEACQUIRED) = 2007) a
JOIN
(SELECT SUM(ACQUISITIONPRICE) AS YEAR_2008
FROM TRANS
WHERE EXTRACT(year from DATEACQUIRED) = 2008) b ON 1=1
JOIN
(SELECT SUM(ACQUISITIONPRICE) AS YEAR_2009
FROM TRANS
WHERE EXTRACT(year from DATEACQUIRED) = 2009) c ON 1=1
If you want the results in a single row, a preferable approach is to use a sub-select with dual as shown in this fiddle:
SELECT
(SELECT SUM(ACQUISITIONPRICE) FROM TRANS WHERE EXTRACT(year from DATEACQUIRED) = 2007) AS YEAR_2007
, (SELECT SUM(ACQUISITIONPRICE) FROM TRANS WHERE EXTRACT(year from DATEACQUIRED) = 2008) AS YEAR_2008
, (SELECT SUM(ACQUISITIONPRICE) FROM TRANS WHERE EXTRACT(year from DATEACQUIRED) = 2009) AS YEAR_2009
FROM dual
When it comes to performance, the only real way to be sure is of course to test it in your particular scenario, but the SUM (CASE... approach shown by #Indra-Prakash-Tiwari may perform better in most cases (if oracle behaves anything like sql server)
Try Use To_Char
Fiddle demo
select TO_CHAR(DATEACQUIRED,'yy') AS Years_Char,Sum(ACQUISITIONPRICE)
FROM trans GROUP BY TO_CHAR(DATEACQUIRED,'yy')