I have a table called Responses where the values are like this:
Client ID
Response Code
Response Value
10047
RA13
University Degree
10047
RA14
Married
10047
RA15
Hispanic
10047
RA16
Employment
10047
RA17
January 29, 1987
I would like to turn the response values in the above table into columns like this:
Client ID
Education level
Marital Status
Race
Income Source
Date of Birth
10047
University Degree
Married
Hispanic
Employment
January 29, 1987
and then I would like to LEFT JOIN this query to another query that has multiple joins already. I was wondering if anyone could help me write this query so that I can left join it to another query?
Please note: I have 10,877 distinct Client IDs in my response table
Thank you!
select .....
from .....
left outer join
( select client_id, education_level, marital_status, race, income_source,
to_date(date_of_birth, 'Month dd, yyyy') as date_of_birth
from responses
pivot (min(response_value)
for response_code in ( RA13 as education_level,
RA14 as marital_status,
RA15 as race,
RA16 as income_source,
RA17 as date_of_birth
)
)
) q
on some_table.client_id = q.client_id
............
One thing to note - in the subquery I also used TO_DATE to convert the date of birth to the proper data type. You may choose to skip that step if you like poor practices.
Related
I have 2 Tables
table a mempur
memberno = member number
purdt = purchase date
amount = purchase amount
table b meminfo
memberno = member number
fname = first name
age = age
select a.memberno,b.fname,sum(a.amount),a.purdt,b.age from mempur a,(select max(purdt) as maxdate,memberno from mempur group by memberno) maxresult,meminfo b
where a.memberno=b.memberno
and a.purdt between '01-JAN-22' and '28-FEB-22'
and a.memberno=maxresult.memberno
and a.purdt=maxresult.maxdate
group by a.memberno,b.fname,a.purdt,b.age
order by a.memberno;
How to get my result with total purchase amount and highest date purchase from table mempur?
I use this query able to show the result but the total amount incorrect between the range.
Anyone help is much appreciated.
my sample data
MEMBERNO PURDT AMOUNT
--------------- --------------- ---------
BBMY0004580 12-AUG-21 823.65
BBMY0004580 12-AUG-21 1709.1
BBMY0004580 26-AUG-21 1015.1
BBMY0004580 28-AUG-21 1105.1
my result only show total amount 1105.1
You can aggregate in mempur and then join to meminfo:
SELECT i.*, p.total_amount, p.maxdate
FROM meminfo i
INNER JOIN (
SELECT memberno, SUM(amount) total_amount, MAX(purdt) maxdate
FROM mempur
WHERE purdt BETWEEN '01-JAN-22' AND '28-FEB-22'
GROUP BY memberno
) p ON p.memberno = i.memberno;
You may use a LEFT join if there are members with no purchases which you want in the results.
Your query gets the maximum purdt and adds up the amount for this date. It also checks whether the maximum purdt is in January or February 2022. If it is, the result gets show, if it is not, you don't show the result. This is not the query you want.
Apart from that, the query looks rather ugly. You are using an ancient join syntax that is hard to read and prone to errors. We used that in the 1980s, but in 1992 explicit joins made it into the SQL standard. You should no longer use this old comma syntax. It is strange to see it still being used. Feels like going to a museum. Then, you are using table aliases. The idea of these is to get a query more readable, but yours even lessen readability, because your alias names a and b are arbitrary. Use mnemonic names instead, e.g. mp for mempur and mi for meminfo. Then, you are comparing the date (I do hope purdt is a date!) with strings. Don't. Use date literals instead.
As to your tables: Are you really storing the age? You will have to update it daily to keep it up-to-date. Better store the date of birth and calculate the age from it in your queries.
Here is a query that gets you the maximum date and the total amount for the given date range:
select memberno, m.name, p.sum_amount, p.max_purdt, m.age
from meminfo m
left outer join
(
select memberno, sum(amount) as sum_amount, max(purdt) as max_purdt
from mempur
where purdt >= date '2022-01-01' and purdt < date '2022-03-01'
group by memberno
) p using (memberno)
order by memberno;
And here is a query that gets you the maximum overall date along with the total amount for the given date range:
select memberno, m.name, p.sum_amount, p.max_purdt, m.age
from meminfo m
left outer join
(
select
memberno,
sum(case when where purdt >= date '2022-01-01' and purdt < date '2022-03-01'
then amount
end) as sum_amount,
max(purdt) as max_purdt
from mempur
group by memberno
) p using (memberno)
order by memberno;
It's an exercise that is not solved in the book in which I am studying.
The goal is to find the seller who has had the highest number of sales per month,
during all the months for which there is registered information. The problem is that I do not know how to divide tuples into periods of one month.
First table is:
Table Sellers
Id_seller
Name_Product
And the other one is:
Table Product
Name_Product
View_datetime
Budget
What did i do?
I made this query:
SELECT id_seller FROM(SELECT id_seller, COUNT(id_seller)
FROM SELLERS INNER JOIN PRODUCT
ON SELLERS.name_product = PRODUCT.name_product
GROUP BY id_seller HAVING COUNT(id_seller)>= 1
ORDER BY 2 DESC)
WHERE ROWNUM = 1;
The query returns me the seller that most sales has done, but not "per month since there are records" as the statement asks. Any ideas? I'm so lost...
The idea is to compare the total sales of each salesman in this month (sysdate), with those of a month ago, two months ago ... so long as there are older records. And get the maximum from each seller. And then you print the seller with more sales from the previous list. If a seller sells 400 products this month(April, the sysdate), but another seller sold in October last year 500, the result would be the second seller . That's what I do not know how to do.
Thanks ^^
You could try this query
select MonthName, id_seller, max(TotalSales) from (
select to_char(sysdate, 'Month') MonthName, sellers.id_seller, count(sellers.id_seller) TotalSales
from sellers inner join product
on sellers.name_product = product.name_product
group by to_char(view_datetime, 'Month'), sellers.id_seller
) tab
group by MonthName, id_seller
There are a few points to make...
The tables are weird. I assume your table sellers would better be called sales, right?
In this example, having count... >= 1 is a no-op. Count could only be 0 if there were no rows at all, in which case there would be no row in the group- by output. You can just leave this count away, here.
To get the sales per month, just add the month to the group by. I.e. group by id_seller, To_date(view_datetime,'YYYYMM').
I have a table called loan with loan amount,annual income, year (MMM-YY format) and member id. I am trying to find the highest loan amount in a year along wit annual income and member id details.
I tried to group the highest loan amount by year using the code
select max(cast(loan_amt as int)),issue_d from loan group by issue_d;
then I wanted also to fetch the member id and annual income information so I wrote the following code
but it is giving me error message for using alias for a column which is cast.
Code:
select a.loan_amt,a.member_id,a.annual_inc,a.issue_d
from
(select loan_amt,member_id,annual_inc,issue_d from loan) a
join
(select max(cast(loan_amt as int)) as ml,issue_d from loan group by issue_d) c
where ((a.issue_d=c.issue_d) and (a.loan_amt=a.ml));
What you want to do is rank the records based on the Amount, per Period, then keep only the top 1 record for each Period.
Use one of the analytic functions that are designed exactly for that purpose -- Hive has a pretty good support of the SQL standard on that topic.
Since you don't say what to do about ties (i.e. what if several loans have the same Amount???) I assume you want just one record chosen randomly...
select X, Y, Z, Period, Amount as TopAmount
from
(select X, Y, Z, Period, cast(StrAmt as double) as Amount,
row_number() over (partition by Period order by cast(StrAmt as double) desc) as TmpRank
from WTF
) TMPWTF
where TmpRank =1
If you want all the records with top Amount then replace row_number with rank or dense_rank (the "dense" stuff would make a difference for the top 2, but not for the top 1)
Using Oracle, PSQL, I am trying to figure out the earliest invoice date for each supplier. That would be simple enough, but I am also trying to figure out the max distribution line on the earliest invoice so I can determine what segment of the business the invoice belongs to. Segment is determined by SEGMENT_NUMBER in the example below. I know a sub query or multiple sub queries are needed here with a group by clause but I am at a loss. The syntax below is not even close, but I wanted to provided something for feedback.
SELECT
SUPPLIER_ID,
INVOICE_NUMBER,
SEGMENT_NUMBER,
MIN(INVOICE_DATE) as EARLIEST_INV_DATE,
MAX(DISTRIBUTION_AMOUNT) as MAX_DIST_LINE
FROM INVOICE_DIST
Use Analytical function like RANK().
SELECT SUPPLIER_ID,
INVOICE_NUMBER,
SEGMENT_NUMBER,
INVOICE_DATE,DISTRIBUTION_AMOUNT
(SELECT SUPPLIER_ID,
INVOICE_NUMBER,
SEGMENT_NUMBER,
INVOICE_DATE,DISTRIBUTION_AMOUNT,
RANK() OVER(PARTITION BY SUPPLIER_ID ORDER BY INVOICE_DATE,DISTRIBUTION_AMOUNT DESC) POSITION FROM INVOICE_DIST) TBL WHERE POSITION=1;
I have dates in this format in my database "01-APR-12" and the column is a DATE type.
My SQL statement looks like this:
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno AND s.salestype = 1
AND (s.salesdate BETWEEN '01-APR-12' AND '31-APR-12');
When I try to do it that way, I get this error -- ORA-01839: date not valid for month specified.
Can I even use the BETWEEN keyword with how the date is setup in the database?
If not, is there another way I can get the output of data that is in that date range without having to fix the data in the database?
Thanks!
April has 30 days not 31.
Change
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno AND s.salestype = 1
AND (s.salesdate BETWEEN '01-APR-12' AND '31-APR-12');
to
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno AND s.salestype = 1
AND (s.salesdate BETWEEN '01-APR-12' AND '30-APR-12');
and you should be good to go.
In case the dates you are checking for range from 1st day of a month to the last day of a month then you may modify the query to avoid the case where you have to explicitly check the LAST day of the month
SELECT DISTINCT c.customerno, c.lname, c.fname
FROM customer c, sales s
WHERE c.customerno = s.customerno
AND s.salestype = 1 AND (s.salesdate BETWEEN '01-APR-12' AND LAST_DAY(TO_DATE('APR-12', 'MON-YY'));
The LAST_DAY function will provide the last day of the month.
The other answers are missing out on something important and will not return the correct results. Dates have date and time components. If your salesdate column is in fact a date that includes time, you will miss out on any sales that happened on April 30 unless they occurred exactly at midnight.
Here's an example:
create table date_temp (temp date);
insert into date_temp values(to_date('01-APR-2014 15:12:00', 'DD-MON-YYYY HH24:MI:SS'));
insert into date_temp values(to_date('30-APR-2014 15:12:00', 'DD-MON-YYYY HH24:MI:SS'));
table DATE_TEMP created.
1 rows inserted.
1 rows inserted.
select * from date_temp where temp between '01-APR-2014' and '30-APR-2014';
Query Result: 01-APR-14
If you want to get all records from April that includes those with time-components in the date fields, you should use the first day of the next month as the second side of the between clause:
select * from date_temp where temp between '01-APR-2014' and '01-MAY-2014';
01-APR-14
30-APR-14