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

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

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

Why are different result between use date_part and exactly date parameter query data in peroid date?

I'm try to count distinct value in some columns in a table.
i have a logic and i try to write in 2 way
But i get diffent results from this two query.
Can any one help to clarify me? I dont know what wrong is code or i think.
SQL
select count(distinct membership_id) from members_membership m
where date_part(year,m.membership_expires)>=2019
and date_part(month,m.membership_expires)>=7
and date_part(day,m.membership_expires)>=1
and date_part(year,m.membership_creationdate)<=2019
and date_part(month,m.membership_creationdate)<=7
and date_part(day,m.membership_creationdate)<=1
;
select count(distinct membership_id) from members_membership m
where m.membership_expires>='2019-07-01'
and m.membership_creationdate<='2019-07-01'
;
I actually think that this is the query you intend to run:
SELECT
COUNT(DISTINCT membership_id)
FROM members_membership m
WHERE
m.membership_expires >= '2019-07-01' AND
m.membership_creationdate < '2019-07-01';
It doesn't make sense for a membership to expire at the same moment it gets created, so if it expires on midnight of 1st-July 2019, then it should have been created strictly before that point in time.
That being said, the problem with the first query is that, e.g., the restriction on the month being on or before July would apply to every year, not just 2019. It is difficult to write a date inequality using the year, month, and day terms separately. For this reason, the second version you used is preferable. It is also sargable, meaning that an index on membership_expires or membership_creationdate can be used.
There is an issue with the first query:
select count(distinct membership_id) from members_membership m
where date_part(year,m.membership_expires)>=2019
and date_part(month,m.membership_expires)>=7
and date_part(day,m.membership_expires)>=1
and date_part(year,m.membership_creationdate)<=2019
and date_part(month,m.membership_creationdate)<=7
and date_part(day,m.membership_creationdate)<=1; -- do you think that any day is less than 1??
-- this condition will be satisfy by only 01-Jul-2019, But I think you need all the dates before 01-Jul-2019
and date_part(day,m.membership_creationdate)<=1 is culprit of the issue.
even membership_creationdate = 15-jan-1901 will not satisfy above condition.
You need to always use date functions on date columns to avoid such type of issue. (Your second query is perfectly fine)
Cheers!!
The reason could be due to a time component.
The proper comparison for the first query is:
select count(distinct membership_id)
from members_membership m
where m.membership_expires >= '2019-07-01' and
m.membership_creationdate < '2019-07-02'
--------------------------------^ not <= ---^ next day
This logic should work regardless of whether or not the "date" has a time component.

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.

Select and group multiple range of dates in oracle SQL

I want to Select the same range of dates and group them by year. In this case I want the total of the bills of a customer per year from September and October.
My Code right now:
SELECT c.name, c.telefonnumber, TO_CHAR(b.billdate, 'YYYY'), sum(b.sume)
FROM customer c, bill b
WHERE b.customerId = c.id
AND b.datum BETWEEN '01.10.2016' AND '30.09.2016'
GROUP BY c.name, c.telefonnumber, TO_CHAR(b.billdate, 'YYYY');
This Query works perfectly but when I want to add another year the result is an endless loop:
AND b.datum BETWEEN '01.10.2016' AND '30.09.2016'
OR b.datum BETWEEN '01.10.2015' AND '30.09.2015'
I also tried to do it in a String way. In this case when I only look for the results of September it works perfectly, but again as soon as I add the OR it becomes again an endless loop:
AND TO_CHAR(kp.tmstmp) LIKE '%.09.%'
OR TO_CHAR(kp.tmstmp) LIKE '%.10.%'
I know I am somehow missing something in the OR operator, but since this is only happening me with dates I am a bit confused.
This query works fine and return 0 rows, I guess - exactly the number of dates between 01.10.2016 and 30.09.2016 :)
If you wish to check several ranges, you should enclose them into braces:
... and
(
b.datum between date '2016-10-01' and date '2017-09-30' or
b.datum between date '2015-10-01' and date '2016-09-30' or
...
) and
...
It looks like your date criteria in the WHERE clause are being phrased incorrectly. Try this instead:
SELECT c.name, c.telefonnumber, TO_CHAR(b.billdate, 'YYYY'), sum(b.sume)
FROM customer c, bill b
WHERE b.customerId = c.id AND
(b.datum BETWEEN TO_DATE('01.10.2016', 'DD.MM.YYYY') AND
TO_DATE('30.09.2016', 'DD.MM.YYYY') OR
b.datum BETWEEN TO_DATE('01.10.2015', 'DD.MM.YYYY') AND
TO_DATE('30.09.2015', 'DD.MM.YYYY'));
I made two changes, namely making certain that the date checks occur in one logical place, surrounded by outer parentheses, and that we use bona fide dates when comparing against the datum column.

SQL left join with grouped table

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