Column name is invalid while using SQL joins [duplicate] - sql

This question already has answers here:
Invalid column name error in WHERE clause, column selected with CASE
(4 answers)
Closed 2 years ago.
I came across a problem that I do not understand.
SELECT T1.CUSTOMER_ID,CONVERT(DATE,T1.DOB,105) [DATE_OF_BIRTH],
T2.TOTAL_AMT,
DATEDIFF(YEAR,CONVERT(DATE,T1.DOB,105), GETDATE()) as AGE
FROM CUSTOMER T1
INNER JOIN TRANSACTIONS T2 ON T1.CUSTOMER_ID=T2.CUST_ID
WHERE AGE>=25 and AGE <=35
Whenever I run this query it gives an error:
age is an invalid column
I am trying to find out those customers whose age lies between 25 to 35.

In your query, Age doesn't exist yet, since WHERE is evaluated before the SELECT list.
Use a derived table:
select * from
(
SELECT T1.CUSTOMER_ID,CONVERT(DATE,T1.DOB,105) [DATE_OF_BIRTH],
T2.TOTAL_AMT,
DATEDIFF(YEAR,CONVERT(DATE,T1.DOB,105), GETDATE()) as AGE
FROM CUSTOMER T1
INNER JOIN TRANSACTIONS T2 ON T1.CUSTOMER_ID=T2.CUST_ID
) dt
WHERE AGE>=25 and AGE <=35

Have you heard about logical query processing?
SELECT T1.CUSTOMER_ID,CONVERT(DATE,T1.DOB,105) [DATE_OF_BIRTH],
T2.TOTAL_AMT,
DATEDIFF(YEAR,CONVERT(DATE,T1.DOB,105), GETDATE()) as AGE
FROM CUSTOMER T1
INNER JOIN TRANSACTIONS T2 ON T1.CUSTOMER_ID=T2.CUST_ID
WHERE DATEDIFF(YEAR,CONVERT(DATE,T1.DOB,105), GETDATE()) >=25 and
DATEDIFF(YEAR,CONVERT(DATE,T1.DOB,105), GETDATE()) <= 35

Related

Amazon SQL job interview question: customers who made 2+ purchases

You have a simple table that has only two fields: CustomerID, DateOfPurchase. List all customers that made at least 2 purchases in any period of six months. You may assume the table has the data for the last 10 years. Also, there is no PK or unique value.
My friend already got the job, despite the fact that he couldn't answer this question. I was curious how this kind of question can be solved.
Thanks
From an abstract view this problem is about efficiently self joining a table with no PK or unique identifier.
This is very tricky as you see there can be scenarios like
a customer making exactly 2 purchase in 6 month that too on same date (which can look like duplicate record)
a customer making >=2 purchase in 6 month on different date(the usual case).
One of the thing that needs to be done here is generate a column that can act
like a unique identifier which can be achieved here using row_number
After having a unique identifier it is easy to join on your required conditions and unique identifier from 1st alias != unique identifier from 2nd alias (meaning joining all rows from both alias except with same row, same row != different row with same data as in 1st scenario)
Putting it all together, it can achieved using
common table expressions to start with a single source of data that includes a manually added unique identifier and then doing the required business
row_number which helps us assign that unique identifier to our single source of data generated in a common table expression.
refer the below query for technical details.
with tempPurchase as (
select *,
row_number() over (order by CustomerID) as rowNumber -- this is crucial part
from purchase
)
select distinct(tp1.CustomerID) from tempPurchase as tp1
join tempPurchase as tp2 on tp1.CustomerID = tp2.CustomerID
and tp1.DateOfPurchase >= tp2.DateOfPurchase
and tp1.DateOfPurchase <= DATEADD(month, 6, tp2.DateOfPurchase)
and tp1.rowNumber != tp2.rowNumber; -- this is crucial part
Refer db fiddle here for complete working solution.
We can try using exists logic here to detect records for the same customer occurring within 6 months. Then, find distinct customers, which implies that any such matching customer has at least two purchases.
SELECT DISTINCT CustomerID
FROM yourTable t1
WHERE EXISTS (SELECT 1 FROM yourTable t2
WHERE t2.CustomerID = t1.CustomerID AND
t2.DateOfPurchase > t1.DateOfPurchase AND
t2.DateOfPurchase <= DATEADD(month, 6, t1.DateOfPurchase));
Note that this answer assumes that there would only be at most one distinct purchase per day by a given customer. A better approach would be:
SELECT DISTINCT CustomerID
FROM yourTable t1
WHERE EXISTS (SELECT 1 FROM yourTable t2
WHERE t2.CustomerID = t1.CustomerID AND
t2.PK <> t1.PK AND
t2.DateOfPurchase >= t1.DateOfPurchase AND
t2.DateOfPurchase <= DATEADD(month, 6, t1.DateOfPurchase));
The above query reads as saying find, for each customer, any relationship between 2 records within 6 months of each other which are distinct purchases. This assumes that the table has a PK primary key column. Ideally, every table should have some kind of logical primary key.
Try this:
SELECT distinct CustomerID
FROM purchase t1
WHERE 1 < (SELECT count(1) FROM purchase t2
WHERE t2.CustomerID = t1.CustomerID AND
t2.DateOfPurchase >= t1.DateOfPurchase AND
t2.DateOfPurchase <= DATEADD(month, 6, t1.DateOfPurchase))
Idea is to pick one record from outer table t1 and check in inner table t2 if there are any purchases made within 6 months including the one which you picked from outer table. If count from subquery is greater than 1 then we have the eligible customer.

How to check another column value to be the highest to determine the latest record that occurs multiple times in Oracle SQL Developer? [duplicate]

This question already has answers here:
Fetch the rows which have the Max value for a column for each distinct value of another column
(35 answers)
Select First Row of Every Group in sql [duplicate]
(2 answers)
Return row with the max value of one column per group [duplicate]
(3 answers)
Get value based on max of a different column grouped by another column [duplicate]
(1 answer)
SQL: getting the max value of one column and the corresponding other columns [duplicate]
(2 answers)
Closed 2 years ago.
I have a table called ro_main_table which stores details of productions such as serial_nr, pr_date_time, machine_nr, record_key etc. I would like to get the distinct machine_nr and record key from ro_main_table where pr_date_time is in last 6 hours. For this I do:
select machine_nr, record_key, pr_date_time from ro_main_table where pr_date_time >= SYSDATE - 6/24;
Which gives me the table below:
MACHINE_NR
RECORD_KEY
PR_DATE_TIME
54
9809
17-DEC-20 04.02.35.000000000 AM
55
9811
17-DEC-20 04.58.22.000000000 AM
55
9817
17-DEC-20 09.17.50.000000000 AM
54
9814
17-DEC-20 07.57.24.000000000 AM
50
9818
17-DEC-20 09.45.22.000000000 AM
However, as you see there might be machines which are started twice during this time (i.e. machine_nr occurs multiple times). If this is the case, I will choose the record which has the highest record_key. For example, for machine 55 it is 9817. How can I achieve this?
Thank you very much in advance!
select machine_nr, max(record_key), pr_date_time
from ro_main_table
where pr_date_time >= SYSDATE - 6/24
group by machine_nr;
this query should get the result you wish
I found a way. I create an inner join like this:
select tt.machine_nr, tt.record_key, tt.pr_date_time
from ro_main_table tt
INNER JOIN
(SELECT machine_nr, MAX(record_key) AS MaxRecordKey
FROM ro_main_table
GROUP BY machine_nr) groupedtt
ON tt.machine_nr = groupedtt.machine_nr
AND tt.record_key = groupedtt.MaxRecordKey
where pr_date_time >= SYSDATE - 6/24;
You can use the window function as follows:
select * from
(select machine_nr, record_key, pr_date_time
row_number() over (partition by machine_nr order by record_key desc) as rn
from ro_main_table where pr_date_time >= SYSDATE - 6/24)
where rn = 1;

Second table columns inner join [duplicate]

This question already has answers here:
In Oracle "AS" alias not working
(3 answers)
SQL syntax or database constrictions?
(1 answer)
Closed 4 years ago.
I am not able to select columns as I am getting SQL command not properly ended error
(
select mobile_no,SIM_NO,START_DATE,END_DATE
from (
select mobile_no,SIM_NO,START_DATE,END_DATE
from employee_1
) myemployee
) join (
( select mobile_1.mobile_no,mobile_1.status
from mobile_1
) as mymobile ) on myemployee.mobile_no = mymobile.mobile_no
Thanks in advance. If this is work i will apply it in my project.
This one might be better:
SELECT mobile_no,
sim_no,
start_date,
end_date
FROM (SELECT mobile_no,
sim_no,
start_date,
end_date
FROM employee_1) myemployee
JOIN
(SELECT mobile_1.mobile_no, mobile_1.status FROM mobile_1) mymobile
ON myemployee.mobile_no = mymobile.mobile_no;
[EDIT, based on a_horse's comment]
SELECT e.mobile_no,
e.sim_no,
e.start_date,
e.end_date
FROM employee_1 e JOIN mobile_1 m ON m.mobile_no = e.mobile_no

No rows fetching but need a value [duplicate]

This question already has answers here:
How to return a default value when no rows are returned from the select statement
(7 answers)
Closed 8 years ago.
I need some help with the following query.
Select date, Source,count(*) as TOTALCOUNT
from Table A
where date = '2014-10-15' and Source = 'EMAIL'
group by date,source
There is no EMAIL source for a particular day. So, it gives no rows.
But I want to get 0 in Totalcount even if EMAIL is not there for that day but can present next day.
It should be like,
Date,Source, Totalcount
15/10/14,Email,0
I used ISNULL function not working as no rows has been resulted.
You could perform a join with a "constant" query. It's an ugly hack, but it should do the trick:
SELECT c.date, c.source, COALESCE(totalcount, 0)
FROM (SELECT '2014-10-15' AS date, 'EMAIL' AS source) c
LEFT JOIN (SELECT date, source, COUNT(*) AS totalcount
FROM a
GROUP BY date, source) a
ON a.date = c.date AND a.source = c.source

TSQL- Rollup SQL 2005

I have the following example code:
create table Details(
name varchar(20),
age int,
weight int,
recordDate Datetime)
--insert data
..query:
SELECT a.name,
a.age,
a.recordDate,
a.weight - (SELECT b.weight
FROM Details
WHERE b.recordDate = dateadd(dd, -1, a.recordDate) as subtable)
FROM Details a
GROUP BY WITH ROLLUP (a.recordDate, a.name, a.age)
I want to see the weight difference between RecordDates for each person and then record total weight different for that person and also for the age group and then grand weight gain/loss. This is not my actual table but just an example.
Problem:
It was complaining about subquery - then I had to use it as table variable: subtable.
Now it is complaining:
Msg 156, Level 15, State 1, Line 14
Incorrect syntax near the keyword 'as'.
Msg 319, Level 15, State 1, Line 18
Incorrect syntax near the keyword 'with'. If this statement is a common table expression or an xmlnamespaces clause, the previous statement must be terminated with a semicolon.
What am I missing?
Typo:
a.weight - (SELECT b.weight
FROM Details
WHERE b.recordDate = dateadd(dd, -1, a.recordDate)
..."b" is being used as a table alias, but it's not actually defined as one.
Next issue is that your GROUP BY doesn't include a.weight, and there's no aggregate function associated with it. Here's my re-write of your query:
SELECT a.name,
a.age,
a.recordDate,
SUM(a.weight - t.weight) 'weight'
FROM DETAILS a
JOIN (SELECT b.recordDate,
b.weight
FROM DETAILS b) t ON t.recordDate = DATEADD(dd, -1, a.recordDate)
GROUP BY (a.recordDate, a.name, a.age) WITH ROLLUP
Try it like this
SELECT
a.name,
a.age,
a.recordDate,
SUM(a.weight - b.weight) as WeightDiff
FROM Details a
JOIN Details b
ON (b.age = a.age
AND b.name = a.name
AND b.recordDate = dateadd(dd, -1, a.recordDate)
)
GROUP BY a.age, a.name, a.recordDate WITH ROLLUP
Don't use AS keyword. You can just directly write {(select * from blah) a}
OK, so the problem is that WITH ROLLUP isn't really the answer you're looking for. This is for creating subtotals not running totals which is what you're after, so using it will give you the total for different combinations of dates rather than a running total, which is what you're after. In the beginning, the query that you want to just get a total that gives you name, age, date and weight loss compared to yesterday is as follows:
select
a.name
,a.age
,a.recordDate
,(SELECT b.weight from Details b WHERE b.recordDate = dateadd(dd,-1,a.recordDate)) - a.weight as weightLossForToday
from details a
Keep in mind that this query will only work if you have exactly 1 record every day. If you have 2 records for a single day or the entries aren't exactly 1 day apart (ie. they include time), then it won't work. In order to get a running total working, you'll need to follow the approach from a question like this.
That should do the trick.
SELECT a.name,a.age,a.recordDate,a.weight-(SELECT b.weight
FROM Details
WHERE b.recordDate=dateadd(dd,-1,a.recordDate))
FROM Details a
GROUP BY (a.recordDate,a.name,a.age)
WITH ROLLUP