SQL left join with grouped table - sql

received some great help on a previous question on this site.
Im new to sql and trying to get my head around this.
From table Tourenstatistik I will get unique rows of data with a date & id.
I am then looking at another table Vtsbreak and summing up the duration for each id on separate dates as there can be more than one entry for the same id on the same date.
I then want to return that sum in a column called duration for the unique id & its date.
I also need to specify the start and finish dates for my query.
I have found something similar but I cant get it to work
coming up with error ORA-00933: SQL command not properly ended.
Any suggestions please?
Select
Tourenstatistik.DATUM "Date",
Tourenstatistik.MITARBEITER "ID",
VtsPause.Duration
From
Tourenstatistik
Where Tourenstatistik.DATUM >= TO_DATE('2017/05/15', 'yyyy/mm/dd') AND Tourenstatistik.DATUM <= TO_DATE('2017/05/16','yyyy/mm/dd')
Left Join
(Select
Vtsbreak.MITARBEITER_NR "ID",
sum(Vtsbreak.DAUER) "Duration",
Vtsbreak.datum "Date"
From
Vtsbreak
Where DATUM >= TO_DATE('2017/04/01', 'yyyy/mm/dd') AND DATUM <= TO_DATE('2017/05/27','yyyy/mm/dd')
group by MITARBEITER_NR, datum;) as VtsPause
On (Tourenstatistik.MITARBEITER = VtsPause.MITARBEITER_NR and Tourenstatistik.DATUM = VtsPause.DATUM)
order by Tourenstatistik.DATUM, Tourenstatistik.MITARBEITER

You are giving the columns aliases in the subquery. You then need to use those aliases. Also, the WHERE clause is misplaced.
Select ts.DATUM as "Date", ts.MITARBEITER as "ID", b."Duration"
From Tourenstatistik ts Left Join
(Select b.MITARBEITER_NR, b.datum, sum(b.DAUER) as "Duration"
From Vtsbreak b
Where b.DATUM >= DATE '2017-04-01' AND
b.DATUM <= DATE '2017-05-27'
group by MITARBEITER_NR, datum
) b
On ts.MITARBEITER = b.MITARBEITER_NR and ts.DATUM = b.DATUM
Where ts.DATUM >= DATE '2017-05-15' and
ts.DATUM <= DATE '2017-05-16'
order by ts.DATUM, ts.MITARBEITER;
You have numerous things wrong with the query, plus a few suggestions:
You had a semicolon in the middle of the query.
You gave columns aliases in the subquery, and then used the original column names.
You had a misplaced WHERE clause.
Recommendations:
Use table abbreviations as table aliases, so the query is easier to write and to read.
Use the date keyword for defining date literals.

Try taking the "as" off of "as VtsPause". Also, get rid of the semicolon after "datum;". I'd also not give column aliases in double quotes on the inline query, especially since you refer to the actual column name in your ON clause.
Also, your first WHERE clause is out of place.
Perhaps this will work:
Select
Tourenstatistik.DATUM
Tourenstatistik.MITARBEITER,
VtsPause.Duration
From
Tourenstatistik
Left Join
(Select
Vtsbreak.MITARBEITER_NR,
sum(Vtsbreak.DAUER) duration,
Vtsbreak.datum
From
Vtsbreak
Where DATUM >= TO_DATE('2017/04/01', 'yyyy/mm/dd')
AND DATUM <= TO_DATE('2017/05/27','yyyy/mm/dd')
group by MITARBEITER_NR, datum) VtsPause
On (Tourenstatistik.MITARBEITER = VtsPause.MITARBEITER_NR
and Tourenstatistik.DATUM = VtsPause.DATUM)
Where Tourenstatistik.DATUM >= TO_DATE('2017/05/15', 'yyyy/mm/dd')
AND Tourenstatistik.DATUM <= TO_DATE('2017/05/16','yyyy/mm/dd')
order by Tourenstatistik.DATUM, Tourenstatistik.MITARBEITER

Related

SQL Why am I getting the invalid identifier error?

I am trying to use columns that I created in this query to create another column.
Let me first my messy query. The query looks like this:
SELECT tb.team, tb.player, tb.type, tb.date, ToChar(Current Date-1, 'DD-MON-YY') as yesterday,
CASE WHEN to_date(tb.date) = yesterday then 1 else 0 end dateindicator,
FROM (
COUNT DISTINCT(*)
FROM TABLE_A, dual
where dateindicator = 1
Group by tb.team
)
What I am trying to do here is:
creating a column with "Yesterday's date"
Using the "Yesterday" column to create another column called dateindicator indicating each row is yesterday's data or not.
then using that dateindicator, I want to count the distinct number of player for each team that has 1 of the dateindicator column.
But I am getting the "invalid identifier" error. I am new to this oracle SQL, and trying to learn here.
You cannot use an Alias in your Select statement.
see here: SQL: Alias Column Name for Use in CASE Statement
you need to use the full toChar(.. in the CASE WHEN.
Also:
Your WHERE-condition (Line 5) doesnt belong there.. it should be:
SELECT DISTINCT .>. FROM .>. WHERE. you have to specify the table first. then you can filter it with where.
If I follow your explanation correctly: for each team, you want to count the number of players whose date column is yesterday.
If so, you can just filter and aggregate:
select team, count(*) as cnt
from mytable
where mydate >= trunc(sysdate) - 1 and mydate < trunc(sysdate)
group by team
This assumes that the dates are stored in column mydate, that is of date datatype.
I am unsure what you mean by counting distinct players; presumably, a given player appears just once per team, so I used count(*). If you really need to, you can change that to count(distinct player).
Finally: if you want to allow teams where no player matches, you can move the filtering logic within the aggregate function:
select team,
sum(case when mydate >= trunc(sysdate) - 1 and mydate < trunc(sysdate) then 1 else 0 end) as cnt
from mytable
group by team

I need to modify query for adding a filter

Please help, I need to add a filter - from and to date. On the column tran_log.Tran_Date in the query given below. Please help me with the updated query.
SELECT
tran_log.FROM_CRN,
ktk_log.DEBIT_ACCT_NO,
ktk_log.TXN_AMOUNT,
ktk_log.EXT_SYSTEM || '-' || ktk_log.REFRENCE_NO AS "Kotak bank ref
number",
case when ktk_log.RETURN_CODE_STATUS = 0 then 'SUC' ELSE 'FAIL' END AS
"Status",
ktk_log.DEBIT_CREDIT_FLAG As "Transaction code",
ktk_log.ERROR_CODE,
KTK_LOG.APP_TYPE as "Merchant code",
tran_log.Tran_Date "Transaction_Date",
tran_log.SOURCE_REF_NO As "Merchant reference number"
FROM
KTK_TRANSACTION_LOG ktk_log
INNER JOIN transaction_log tran_log on TRAN_LOG.TRAN_REF_NO =
KTK_LOG.EXT_SYSTEM || '-' || KTK_LOG.REFRENCE_NO;
I THINK THIS COULD BE HELPFUL
SELECT * FROM TABLE
WHERE tran_log BETWEEN FRMDATE AND TODATE;
What is your actual question?
How to filter query results? Use a WHERE clause.
Whether to put the condition in a WHERE clause or extend your ON clause? Just decide. Both methods are equally okay. Extending the ON clause would have the advantage that you could change the inner join to an outer join more easily, if you ever want to do that.
How to use date literals? That's DATE 'yyyy-mm-dd', e.g. DATE '2019-06-20'.
How to compare dates? In Oracle there is no difference betwen a date and a datetime. The DATE datatype allows for a time with the date. So it is often preferred to use >= and < when checking against a date range. E.g. for April: where mydate >= date '2019-04-01' and mydate < '2019-05-01'. Thus you get everything from the first till the last nanosecond :-)

Can someone help me with this join

I need it to give me me a total of 0 for week 33 - 39, but I'm really bad with joining 3 tables and I cant figure it out
Right now it only gives me an answer for dates that there are actual records in the tracker_weld_table.
SELECT SUM(tracker_parts_archive.weight),
WEEK(mycal.dt) as week
FROM
tracker_parts_archive, tracker_weld_archive
RIGHT JOIN
(SELECT dt FROM calendar_table WHERE dt >= '2018-7-1' AND dt <= '2018-10-1') as mycal
ON
weld_worker = '133'AND date(weld_dateandtime) = mycal.dt
WHERE
tracker_weld_archive.tracker_partsID = tracker_parts_archive.id
GROUP BY week
I think you are trying for something like this:
SELECT WEEK(c.dt) as week, COALESCE(SUM(tpa.weight), 0)
FROM calendar_table c left join
tracker_weld_archive tw
on date(tw.weld_dateandtime) = c.dt left join
tracker_parts_archive tp
on tw.tracker_partsID = tp.id and tp.weld_worker = 133
WHERE c.dt >= '2018-07-01' AND c.dt <= '2018-10-01'
GROUP BY week
ORDER BY week;
Notes:
You want to keep all (matching) rows in the calendar table, so it should be first.
All subsequent joins should be LEFT JOINs.
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
Write out the full proper date constant -- YYYY-MM-DD. This is an ISO-standard format.
I am guessing that weld_worker is a number, so single quotes are not needed for the comparison.
First, lets start with understanding what you want.. You want totals per week. This means there will be a "GROUP BY" clause (also for any MIN(), MAX(), AVG(), SUM(), COUNT(), etc. aggregates). What is the group BY basis. In this scenario, you want per week. Leading to the next part that you want for a specific date range qualified per your calendar table.
I would start in order what WHAT filtering criteria first. Also, ALWAYS TRY to identify all table( or alias).column in your queries so anyone after you knows where the columns are coming from, especially when multiple tables. In this case "ct" is the ALIAS for "Calendar_Table"
SELECT
ct.dt
from
calendar_table ct
where
ct.dt >= '2018-07-01'
AND ct.dt <= '2018-10-01'
Now, the above date looks to be INCLUSIVE of October 1 and looks like you are trying to generate a quarterly sum from July, Aug, Sept. I would change to LESS than Oct 1.
Now, your calendar has many days and you want it grouped by week, so the WEEK() function gets you that distinct reference without explicitly checking every date. Also, try NOT to use reserved keywords as final column names... makes for confusion later on sometimes.
I have aliased the column name as "WeekBasis". Here, I did a COUNT(*) just to show the total days and the group by showing it in context.
SELECT
WEEK( ct.dt ) WeekBasis,
MIN( ct.dt ) as FirstDayOfThisWeek,
MAX( ct.dt ) as LastDayOfThisWeek,
COUNT(*) as DaysInThisWeek
from
calendar_table ct
where
ct.dt >= '2018-07-01'
AND ct.dt <= '2018-10-01'
group by
WEEK( ct.dt )
So, at this point, we have 1 record per week within the date period you are concerned,
but I also grabbed the earliest and latest dates just to show other components too.
Now, lets get back to your extra tables. We know the dates in question, now need to
get the details from the other tables (which is lacking in the post. You should post
critical components such as how tables are related via common / joined column basis.
How is tracker_part_archive related to tracker_weld_archive??
To simplify your query, you dont even NEED your calendar table as the welding
table HAS a date field and you know your range. Just query against that directly.
IF your worker's ID is numeric, don't add quotes around it, just leave as a number.
SELECT
WEEK( twa.Weld_DateAndTime ) WeekBasis,
COUNT(*) WeldingEntriesDone,
SUM(tpa.weight) TotalWeight
from
tracker_weld_archive twa
JOIN tracker_parts_archive tpa
-- GUESSING on therelationship here.
-- may also be on a given date too???
-- all pieces welded by a person on a given date
ON twa.weld_worker = tpa.weld_worker
AND twa.Weld_DateAndTime = tpa.Weld_DateAndTime
where
twa.Weld_Worker = 133
AND twa.Weld_DateAndTime >= '2018-07-01'
AND twa.Weld_DateAndTime <= '2018-10-01'
group by
WEEK( twa.Weld_DateAndTime )
IF you provide the table structures AND sample data, this can be refined a bit more for you.

Oracle query displays data by month and year

I want to display the amount of data by month and year. This is an example of displaying data by date:
select count(*) from db.trx where trxdate = to_date('2018-04-23','yyyy-mm-dd')
When I try to display the amount of data by month and year, no query results appear. Is there something wrong with the query?
The query:
select count(*) from db.trx where trxdate = to_date('2018-04','yyyy-mm')
You need to apply the function to trxdate. Using your logic:
SELECT Count(*)
FROM olap.trxh2hpdam
WHERE To_char(trxdate, 'YYYY-MM') = '2018-04';
However, I strongly recommend that you use direct date comparisons:
WHERE trxdate >= date '2018-04-01'
AND
trxdate < date '2018-05-01'
This will allow the database to use an index on trxdate.
There are a couple of ways of accomplishing what you're trying to do. Which one works for you will depend on your database design (for example, the indexes you've created). One way might be this:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE TRUNC(trxdate, 'MONTH') = DATE'2018-04-01';
This will round the date down to the first of the month (and, of course, remove any time portion). Then you simply compare it to the first of the month for which you want the data. However, unless you have an index on TRUNC(trxdate, 'MONTH'), this may not be the best course of action; if trxdate is indexed, you'll want to use:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE trxdate >= DATE'2018-04-01'
AND trxdate < DATE'2018-05-01';
There are a number of functions at your disposal in Oracle (e.g. ADD_MONTHS()) in the event that the date you use in your query is supposed to be dynamic rather than static.
Just FYI, there is no reason not to use ANSI date literals when trying to retrieve data by day as well. I'm not sure your original query is a good example of getting data for a particular day, since the Oracle DATE datatype does at least potentially include a time:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE trxdate >= DATE'2018-04-23'
AND trxdate < DATE'2018-04-24';
or:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE TRUNC(trxdate) = DATE'2018-04-23';
EDIT
In case the month and year are dynamic, I would build a date from them (e.g., TO_DATE('<year>-<month>-01', 'YYYY-MM-DD')) and then use the following query:
SELECT COUNT(*) FROM olap.trxh2hpdam
WHERE trxdate >= TO_DATE('<year>-<month>-01', 'YYYY-MM-DD')
AND trxdate < ADD_MONTHS( TO_DATE('<year>-<month>-01', 'YYYY-MM-DD'), 1 );
Hope this helps.

ORA-00907: missing right parenthesis using count with expression inside it

SELECT Hotel_Name, COUNT(H_CHECK.Hotel_checkIn >= 'JUL-1-2016' AND H_CHECK.Hotel_checkIn <= 'JUL-31-2016') FROM HOTEL, H_CHECK
GROUP BY Hotel_Name
ORA-00907: missing right parenthesis
I have tried putting Parenthesis in many ways, but I couldn't find the solution. I'm using Oracle Application Express 11G.
This is the query:
Display the hotel name that has more than 2 customers checked in on July 2016.
Once you fix your immediate syntax problem, you need proper JOIN syntax.
One way to fix the problem is simply to move the conditions to a WHERE clause, resulting in a query like this:
SELECT Hotel_Name, COUNT(hc.hotel_id)
FROM HOTEL h LEFT JOIN
H_CHECK hc
ON h.hotel_id = hc.hotel_id -- I don't know what the right join condition is
WHERE hc.Hotel_checkIn >= DATE '2016-07-01' AND
hc.Hotel_checkIn <= DATE '2016-07-31'
GROUP BY Hotel_Name;
You cannot count based on condition in Select statement of your sql query.
COUNT (
H_CHECK.Hotel_checkIn >= 'JUL-1-2016'
AND H_CHECK.Hotel_checkIn <= 'JUL-31-2016')
This is wrong. You can do it like>
SELECT Hotel_Name,
COUNT (1)
FROM HOTEL
join H_CHECK
ON H_CHECK.Hotel_checkIn >= 'JUL-1-2016'
AND H_CHECK.Hotel_checkIn <= 'JUL-31-2016'
GROUP BY Hotel_Name
having count(1) > 2;
You're missing the CASE ... END from your conditions inside your count. You're after something like:
SELECT Hotel_Name,
COUNT(case when H_CHECK.Hotel_checkIn >= 'JUL-1-2016'
AND H_CHECK.Hotel_checkIn <= 'JUL-31-2016'
then 1
end)
FROM HOTEL, H_CHECK
GROUP BY Hotel_Name;
However, there are a number of concerns I have regarding your query:
if your hotel_checkin column is of DATE datatype, then you should be comparing it to DATEs not strings. I.e. H_CHECK.Hotel_checkIn >= to_date('07-01-2016', 'mm-dd-yyyy') - this way, you avoid relying on implicit conversion of the string into a date, which relies on your NLS_DATE_FORMAT parameter setting. This could be changed and may cause your query to fail.
FROM HOTEL, H_CHECK Don't use the old-style method of joining; instead, use the ANSI style method: FROM hotel cross join h_check
Did you really mean the join to be a cross join or did you forget to add the join conditions?
You should alias the hotel_name column to aid maintainability.
You should also give your count column a name.
Since you're only counting rows with a checkin between 1st and 31st July 2016, you should move this condition into the where clause (as XING has shown in their answer) *unless* you need to also show hotels that don't have any checkins within that time period.
Your condition assumes that there are no time elements to the hotel_checkin column - ie. everything is set to midnight. If, however, you could have a date with a time, bear in mind that your count will ignore all rows with a checkin date of 31st July 2016 that are after midnight. In which case, your upper bound needs to change to: H_CHECK.Hotel_checkIn < to_date('08-01-2016', 'mm-dd-yyyy')