Oracle SQL help - sql

I posted on Friday (sql multiple count) and had a few responses.
Having tried to implement them today, I keep getting the same error.
My SQL code now is:
SELECT MBDDX_STUDY.STUDY_NAME,
COUNT(MBDDX_EXPERIMENT.STUDY_ID)
AS NUMBER_OF_EXPERIMENTS
FROM MBDDX_STUDY
INNER JOIN MBDDX_EXPERIMENT
ON MBDDX_STUDY.ID = MBDDX_EXPERIMENT.STUDY_ID
INNER JOIN (SELECT COUNT(MBDDX_TREATMENT_GROUP.GROUP_NO)
FROM MBDDX_TREATMENT_GROUP)
ON MBDDX_TREATMENT_GROUP.STUDY_ID = MBDDX_STUDY.ID
GROUP BY MBDDX_STUDY.STUDY_NAME
I keep getting the error:
ORA-00904: "MBDDX_TREATMENT_GROUP"."STUDY_ID": invalid identifier
Is it because it is outside of the inner join bracket, i.e. out of scope? I am very new to SQL and cannot understand why it wont work. I can get it working using select subqueries (without joins) but I want to also be able to work with joins.
If it matters any I am using Toad for Oracle.
Thanks.

Because you join with a query. Give a name to that query, and refer to it that way:
SELECT MBDDX_STUDY.STUDY_NAME
, COUNT ( MBDDX_EXPERIMENT.STUDY_ID )
AS NUMBER_OF_EXPERIMENTS
FROM MBDDX_STUDY
INNER JOIN MBDDX_EXPERIMENT
ON MBDDX_STUDY.ID = MBDDX_EXPERIMENT.STUDY_ID
inner JOIN ( SELECT study_id, COUNT ( MBDDX_TREATMENT_GROUP.GROUP_NO )
FROM MBDDX_TREATMENT_GROUP group by study_id ) AS my_query
ON my_query.STUDY_ID = MBDDX_STUDY.ID
GROUP BY MBDDX_STUDY.STUDY_NAME

For one thing, a subquery must have an alias. Change:
inner JOIN ( SELECT COUNT ( MBDDX_TREATMENT_GROUP.GROUP_NO )
FROM MBDDX_TREATMENT_GROUP )
ON MBDDX_TREATMENT_GROUP.STUDY_ID = MBDDX_STUDY.ID
to
inner JOIN ( SELECT COUNT ( MBDDX_TREATMENT_GROUP.GROUP_NO )
FROM MBDDX_TREATMENT_GROUP ) as CountAlias
ON MBDDX_TREATMENT_GROUP.STUDY_ID = MBDDX_STUDY.ID
The second thing is that you have to include all columns you plan to use. Right now, the subquery just selects a count, but the ON clause references STUDY_ID. You can fix that by including STUDY_ID in the subquery select list, like:
inner JOIN (
SELECT STUDY_ID
, COUNT(MBDDX_TREATMENT_GROUP.GROUP_NO) as GroupCount
FROM MBDDX_TREATMENT_GROUP) as CountAlias
ON MBDDX_TREATMENT_GROUP.STUDY_ID = MBDDX_STUDY.ID
Now after that, you might hit other issues, but I'm hoping this will get you started.

Related

Trying to update column values in SQL Server based on time of insertion and getting "The column "ID" was specificed multiple times for "p""

Here is my query that's throwing the "The column "ID" was specified multiple times for "p"":
update tracking.tag set
tracking.tag.PageViewID = p.id
, tracking.tag.BrowserInfoID = p.BrowserInfoID
from (
select
t.id, t.[name], t.VisitID, t.CreatedDate, p.id, p.VisitID, p.BrowserInfoID
from [Tracking].[Tag] as t
inner join (
select id, visitid, BrowserInfoID, createddate, uri
from [tracking].[PageView]
) as p on abs(datediff(second, p.CreatedDate, t.createddate)) < 1 and p.VisitID = t.VisitID
order by 1 desc
) as p
I've seen quite a few questions with the same error on SO but can't seem to see what to apply in this scenario. Any help is greatly appreciated.
Unfortunately there is a lot broken with your statement. The error you are getting is the least of your worries and it in fact just a typo. Let me go through them.
The error: if you consider the following query, which is in essence what you have, how does SQL Server know which of the 2 columns in your sub-query to refer to? They are both called id! Hence if you need to select both columns you need to alias one of them to a unique name.
select id
from (
select
t.id, p.id
from [Tracking].[Tag] as t
inner join [tracking].[PageView] as p
on ABS(datediff(second, p.CreatedDate, t.createddate)) < 1
and p.VisitID = t.VisitID
) as p
Fixed:
select id -- Now we have a unique id column, so SQL Server knows which to select.
from (
select
t.id TagID, p.id
from [Tracking].[Tag] as t
inner join [tracking].[PageView] as p
on ABS(datediff(second, p.CreatedDate, t.createddate)) < 1
and p.VisitID = t.VisitID
) as p
You have a syntax error with your ORDER BY, you can't order a sub-query in that way as it doesn't mean anything.
This is a recommendation, but don't reuse the same table alias (in your case P) in multiple nested sub-queries because its really confusing to know which table/derived table you are referencing.
Your inner-most sub-query is un-necessary, just join the table directly.
Finally you aren't actually joining the table you are updating onto the query you are producing, yes you do have a join inside, but thats not the same table reference as the one you are updating. I assume thats why you have attempted to add an ORDER BY inside your sub-query despite the fact that its giving you a syntax error. In fact all you need is a simple UPDATE + JOIN as follows:
-- Note you use the table alias here for the update rather than the table name
update t set
PageViewID = p.id
, BrowserInfoID = p.BrowserInfoID
-- I assume this select is what you were running into issues with as you tried to test that your update was correct.
-- In this format you no longer need to alias the duplicate column names, but you could for clarity
-- select t.id TagID, t.[name], t.VisitID TagVisitId, t.CreatedDate, p.id, p.VisitID, p.BrowserInfoID
from [Tracking].[Tag] as t
inner join [tracking].[PageView] as p on abs(datediff(second, p.CreatedDate, t.createddate)) < 1 and p.VisitID = t.VisitID

Unable to Group on MSAccess SQL multiple search query

please can you help me before I go out of my mind. I've spent a while on this now and resorted to asking you helpful wonderful people. I have a search query:
SELECT Groups.GroupID,
Groups.GroupName,
( SELECT Sum(SiteRates.SiteMonthlySalesValue)
FROM SiteRates
WHERE InvoiceSites.SiteID = SiteRates.SiteID
) AS SumOfSiteRates,
( SELECT Count(InvoiceSites.SiteID)
FROM InvoiceSites
WHERE SiteRates.SiteID = InvoiceSites.SiteID
) AS CountOfSites
FROM (InvoiceSites
INNER JOIN (Groups
INNER JOIN SitesAndGroups
ON Groups.GroupID = SitesAndGroups.GroupID
) ON InvoiceSites.SiteID = SitesAndGroups.SiteID)
INNER JOIN SiteRates
ON InvoiceSites.SiteID = SiteRates.SiteID
GROUP BY Groups.GroupID
With the following table relationship
http://m-ls.co.uk/ExtFiles/SQL-Relationship.jpg
Without the GROUP BY entry I can get a list of the entries I want but it drills the results down by SiteID where instead I want to GROUP BY the GroupID. I know this is possible but lack the expertise to complete this.
Any help would be massively appreciated.
I think all you need to do is add groups.Name to the GROUP BY clause, however I would adopt for a slightly different approach and try to avoid the subqueries if possible. Since you have already joined to all the required tables you can just use normal aggregate functions:
SELECT Groups.GroupID,
Groups.GroupName,
SUM(SiteRates.SiteMonthlySalesValue) AS SumOfSiteRates,
COUNT(InvoiceSites.SiteID) AS CountOfSites
FROM (InvoiceSites
INNER JOIN (Groups
INNER JOIN SitesAndGroups
ON Groups.GroupID = SitesAndGroups.GroupID
) ON InvoiceSites.SiteID = SitesAndGroups.SiteID)
INNER JOIN SiteRates
ON InvoiceSites.SiteID = SiteRates.SiteID
GROUP BY Groups.GroupID, Groups.GroupName;
I think what you are looking for is something like the following:
SELECT Groups.GroupID, Groups.GroupName, SumResults.SiteID, SumResults.SumOfSiteRates, SumResults.CountOfSites
FROM Groups INNER JOIN
(
SELECT SitesAndGroups.SiteID, Sum(SiteRates.SiteMonthlySalesValue) AS SumOfSiteRates, Count(InvoiceSites.SiteID) AS CountOfSites
FROM SitesAndGroups INNER JOIN (InvoiceSites INNER JOIN SiteRates ON InvoiceSites.SiteID = SiteRates.SiteID) ON SitesAndGroups.SiteID = InvoiceSites.SiteID
GROUP BY SitesAndGroups.SiteID
) AS SumResults ON Groups.SiteID = SumResults.SiteID
This query will group your information based on the SiteID like you want. That query is referenced in the from statement linking to the Groups table to pull the group information that you want.

SQL Server Join on Select statement using count() and group by

I have two tables in SQL Server, tbl_disputes and tbl_disputetypes. The tbl_disputes table contains a foreign key column disputetype. The table tbl_disputetypes contains the primary key field disputetypeid and disputetypedesc. The following query gives me a count of each disputetype from the tbl_disputes table.
select disputetype, count(disputetype) as numberof
from tbl_disputes
group by disputetype
What sort of join or subquery do I need to use to display the
tbl_disputetypes.dbo.disputetypedesc instead of tbl_disputes.dbo.disputetype?
EDIT Issue was because disputetypedesc was set as TEXT. I changed it to nvarchar, and the following query worked:
SELECT
tbl_disputetypes.disputetypedesc,
count(tbl_disputetypes.disputetypedesc)
FROM
tbl_disputes Left OUTER JOIN
tbl_disputetypes ON tbl_disputes.disputetype = tbl_disputetypes.disputetypeid
group by tbl_disputetypes.disputetypedesc
Unless I'm missing something, you can just LEFT JOIN the description:
select disputetypedesc, count(disputetype) as numberof
from tbl_disputes d
LEFT JOIN tbl_disputetypes dt
ON dt.disputetypeid = d.disputetype
group by disputetypedesc
Assuming 2005+:
WITH x(t, numberof) AS
(
SELECT disputetype, COUNT(*)
FROM tbl_disputes
GROUP BY disputetype
)
SELECT dt.disputetypedesc, x.numberof
FROM tbl_disputetypes AS dt
INNER JOIN x ON dt.disputetype = x.t;
A simple JOIN?
select
DT.disputetypedesc, count(*) as numberof
from
tbl_disputes D
JOIN
tbl_disputetypes DT ON D.disputetype = DT.disputetype
group by
DT.disputetypedesc
The basic idea is that you will need a sub-query. Something like this will work:
select disputetypedesc, disputetype, numberof
from (select disputetype, count(disputetype) numberof
from tbl_disputes
group by disputetype) t left outer join
tbl_disputetypes on t.disputetype = tbl_disputetypes.disputetype
I am not sure if I understand your question however you should be able to select all columns using a query similar to the code sample below.
The following query will join the two tables by the disputetypeid column. I changed the format of the SQL statement however you can obviously format it however you would like.
SELECT tbl_disputetypes.disputetypedesc
, tbl_disputes.*
, <any_column_from_either_table>
FROM tbl_disputes
INNER JOIN tbl_disputetypes
ON tbl_disputes.disputetypeid = tbl_disputetypes.disputetypeid

sql multiple count

I have 3 tables, where the first one's primary key, is the foreign key in the other 2.
I want to extract one field from the first table, and then a count from the other 2, all joined using the pk and fk. This is what I have so far:
SELECT MBDDX_STUDY.STUDY_NAME, COUNT(MBDDX_EXPERIMENT.STUDY_ID) AS NUMBER_OF_EXPERIMENTS
FROM MBDDX_STUDY
INNER JOIN MBDDX_EXPERIMENT
ON MBDDX_STUDY.ID=MBDDX_EXPERIMENT.STUDY_ID
INNER JOIN (SELECT COUNT(MBDDX_TREATMENT_GROUP.GROUP_NO) AS NUMBER_OF_GROUPS
FROM MBDDX_TREATMENT_GROUP)
ON MBDDX_TREATMENT_GROUP.STUDY_ID = MBDDX_STUDY.ID
group by MBDDX_STUDY.STUDY_NAME, MBDDX_TREATMENT_GROUP.STUDY_ID
But, i get an error saying that the MBDDX_TREATMENT_GROUP.STUDY_ID , in the penultimate line is an invalid indentifier. It is a correct table.
Any advise please.
Thanks.
You're getting the error because that column is not in your SELECT, so it can't GROUP BY a field it doesn't have.
The subquery syntax doesn't seem to make any sense to me. You've made a query that counts all rows of MBDDX_TREATMENT_GROUP, independently of the STUDY_ID, and then tries to join it into the table with a join condition that doesn't refer to anything in the subquery's results (and can't, without an alias).
Why not use a simple join? Assuming MBDDX_EXPERIMENT also has a primary key ID, you can do it with a COUNT-DISTINCT:
SELECT
MBDDX_STUDY.ID, MBDDX_STUDY.STUDY_NAME,
COUNT(DISTINCT MBDDX_EXPERIMENT.ID) AS NUMBER_OF_EXPERIMENTS
COUNT(DISTINCT MBDDX_TREATMENT_GROUP.GROUP_NO) AS NUMBER_OF_GROUPS
FROM
MBDDX_STUDY
INNER JOIN MBDDX_EXPERIMENT ON MBDDX_EXPERIMENT.STUDY_ID=MBDDX_STUDY.ID
INNER JOIN MBDDX_TREATMENT_GROUP ON MBDDX_TREATMENT_GROUP.STUDY_ID=MBDDX_STUDY.ID
GROUP BY
MBDDX_STUDY.ID, MBDDX_STUDY.STUDY_NAME
(MBDDX_STUDY.STUDY_NAME technically shouldn't be necessary to include in the GROUP BY expression according to ANSI SQL as it has a functional dependency on STUDY_ID. However it is necessary on Oracle, which can't spot the dependency.)
You don't need to group by this field (MBDDX_TREATMENT_GROUP.STUDY_ID). It should be just group by MBDDX_STUDY.STUDY_NAME
If my understanding is correct,You need a record from first table and have the count of related records in the other two tables.Here is the answer
SQL:Getting count from many tables for a user record in USER table.Whats the best approach?
It looks like you need to alias the second subquery and need to include something to join on.
It also looks like you aren't using the count you have in the subquery as well.
Try this out:
SELECT MBDDX_STUDY.STUDY_NAME
, COUNT(MBDDX_EXPERIMENT.STUDY_ID) AS NUMBER_OF_EXPERIMENTS
FROM MBDDX_STUDY
INNER JOIN MBDDX_EXPERIMENT
ON MBDDX_STUDY.ID=MBDDX_EXPERIMENT.STUDY_ID
INNER JOIN (SELECT STUDY_ID, COUNT(MBDDX_TREATMENT_GROUP.GROUP_NO) AS NUMBER_OF_GROUPS
FROM MBDDX_TREATMENT_GROUP GROUP BY MBDDX_TREATMENT_GROUP.STUDY_ID) xx
ON xx.STUDY_ID = MBDDX_STUDY.ID
GROUP BY MBDDX_STUDY.STUDY_NAME, xx.STUDY_ID
For what you really want to do, you want OUTER JOINs.
WITH number_of_experiments
AS ( SELECT study_id
, count ( * ) CNT
FROM MBDDX_EXPERIMENT
group by study_id )
, number_of_groups
as ( select study_id
, count ( * ) CNT
FROM mbddx_treatment_group
group by study_id )
select study_name
, coalesce(noex.cnt,0)
, coalesce(notr.cnt,0)
from mbddx_study
outer join number_of_experiments
as noex
using ( study_id )
outer join number_of_groups
as nogr
using ( study_id )

MS-SQL problem - Only one expression can be specified in the select list

I write the following query:
select
id,
(select NameEn from [Campaign] where id=CampaignId) as CampaignName,
createdDate,
(select Name, IdNo, Email, MobileNo from [Members] where id=MemberId)
from
Transactions
and error occurs:
"Only one expression can be specified in the select list when the subquery is not introduced with EXISTS."
How can I rewrite the SQL to make it correct?
You need to use proper (inner|left|...) join syntax.
Something like:
select
t.id,
c.NameEn,
t.createdDate,
m.Name,
m.IdNo,
m.Email,
m.MobileNo
from
[Transactions] t
inner join [Campaign] c on c.id = t.CampaignId
inner join [Members] m on m.id = t.MemberId
Also, in your original code, one of
select NameEn from [Campaign] where id=CampaignId
or
select Name,IdNo,Email,MobileNo from [Members] where id=MemberId
might be returning more than one row for each row of [Transactions], which would be illegal.