SQL Too few parameters when using WHERE clause and GROUP BY - sql

I'm trying to write a query that will display a list of actors who star in at least 1 movie. I'm getting a "Too few parameters. Expected 2." error when I put the WHERE clause in. How do I fix this?
<cfquery name="qry1" datasource="torture">
SELECT
Actors.ActorID,
Actors.First_Name + ' ' + Actors.Last_Name AS Fullname,
COUNT( Title ) AS Titles
FROM
Actors
RIGHT JOIN Videos ON Actors.ActorID = Videos.ActorID
WHERE
Fullname <> NULL AND
Titles > 0
GROUP BY
Actors.ActorID,
Actors.First_name,
Actors.Last_Name;
</cfquery>
<cfform name="form" action="Page7Receiver.cfm">
<cfselect name="actor"
query="qry1"
value="ActorID"
display="FullName"
required="Yes"
multiple="No"
size="8">
</cfselect>
<br><input type="Submit" value="Submit">
</cfform>

The problem is caused by referencing names in your WHERE query that don't exist yet (Fullname and Titles).
Despite that SQL is in SELECT... FROM... WHERE... GROUP BY... HAVING... ORDER BY... order, in reality the SELECT is evaluated at the end, so your Fullname and Titles columns are not yet available in your WHERE clause.
I suggest reformulating the query like so:
SELECT
Actors.ActorId,
Actors.First_Name + ' ' + Actors.Last_Name AS FullName,
COALESCE( VideoInfo.VideoCount, 0 ) AS Titles
FROM
Actors
LEFT OUTER JOIN
(
SELECT
ActorId,
COUNT( * ) AS VideoCount
FROM
Videos
GROUP BY
ActorId
) AS VideoInfo ON Actors.ActorId = VideoInfo.ActorId
WHERE
COALESCE( VideoInfo.VideoCount, 0 ) > 0
AND
Actors.First_Name IS NOT NULL
AND
Actors.Last_Name IS NOT NULL
If we change it to an INNER JOIN then we can skip the Titles > 0 check because the nature of INNER JOIN means if an Actor has no Videos then there won't be a table-join on that ActorId anyway.
SELECT
Actors.ActorId,
Actors.First_Name + ' ' + Actors.Last_Name AS FullName,
VideoInfo.VideoCount AS Titles
FROM
Actors
INNER JOIN
(
SELECT
ActorId,
COUNT( * ) AS VideoCount
FROM
Videos
GROUP BY
ActorId
) AS VideoInfo ON Actors.ActorId = VideoInfo.ActorId
WHERE
Actors.First_Name IS NOT NULL
AND
Actors.Last_Name IS NOT NULL
Note, the <> NULL is not valid SQL. NULL is special: you have to use IS NOT NULL or IS NULL instead.

Related

How to use a dynamically created column in a WHERE clause

I created a table column called name cause the firstname and the lastname are stored in two separate columns. To solve the problem I use CONCAT in the SELECT statement. However if I want to search for a specific value inside the name column SQL returns the error:
Unknown column 'name' in 'where clause'
Is it possible to search in a dynamically created column in a SELECT statement?
SELECT
u.ID AS id,
CONCAT(umFirstName.meta_value, " ", umLastName.meta_value) AS name,
u.user_email AS email,
umChatStatus.meta_value AS chatStatus,
umCallStatus.meta_value AS callStatus,
umRef.meta_value AS reference
FROM
wp_users AS u
LEFT JOIN
wp_usermeta AS um ON u.ID = um.user_id
LEFT JOIN
wp_usermeta AS umFirstName ON u.ID = umFirstName.user_id
AND umFirstName.meta_key = "_ctbFirstName"
LEFT JOIN
wp_usermeta AS umLastName ON u.ID = umLastName.user_id
AND umLastName.meta_key = "_ctbLastName"
LEFT JOIN
wp_usermeta AS umChatStatus ON u.ID = umChatStatus.user_id
AND umChatStatus.meta_key = "_ctbChatSessionStatus"
LEFT JOIN
wp_usermeta AS umCallStatus ON u.ID = umCallStatus.user_id
AND umCallStatus.meta_key = "_ctbCallSessionStatus"
LEFT JOIN
wp_usermeta AS umRef ON u.ID = umRef.user_id
AND umRef.meta_key = "_ctbRef"
WHERE
um.meta_key = "wp_capabilities"
AND um.meta_value IN ('a:1:{s:8:"employee ";b:1;}')
AND u.id LIKE '%%'
OR name LIKE '%%'
OR u.user_email LIKE '%%'
OR umChatStatus.meta_value LIKE '%%'
OR umCallStatus.meta_value LIKE '%%'
OR umRef.meta_value LIKE'%%'
ORDER BY
id DESC
LIMIT 0, 20
UPDATE
Got it working like it should. Thanks to Caius Jard metioning to -always use parentheses- in a AND and OR mix. For someone that is interested in the solution.
SQL queries are evaluated in the following order (just the blocks you've used):
FROM (including joins)
WHERE
SELECT
ORDER BY
This means that something you create in the SELECT, like CONCAT(Firstname, ' ', LastName) simply doesn't exist at the time the WHERE is evaluated
You have a couple of options:
Use CONCAT(Firstname, ' ', LastName) in the WHERE clause too
SELECT
CONCAT(Firstname, ' ', LastName) AS N
FROM
person
WHERE
CONCAT(Firstname, ' ', LastName) = 'John smith'
Turn the whole query into a sub query and use the thing you created in the outer
SELECT
x.N
FROM
(
SELECT
CONCAT(Firstname, ' ', LastName) AS N
FROM
person
) x
WHERE
x.N = 'John smith'
This form can also be written as:
WITH x AS
(
SELECT
CONCAT(Firstname, ' ', LastName) AS N
FROM
person
)
SELECT x.N
FROM x
WHERE x.N = 'John smith'
These latter forms are useful when you want to use it multiple times and don't want to keep repeating some massive calculation:
WITH x AS
(
SELECT
SUM(Points) / DATEDIFF(day, MIN(GameStart), MAX(GameEnd)) as PointsPerDay
FROM
Games
GROUP BY PlayerId
)
SELECT
CASE
WHEN PointsPerDay < 100 THEN 'Newbie'
WHEN PointsPerDay < 200 THEN 'Seasoned'
WHEN PointsPerDay < 300 THEN 'Advanced'
ELSE 'Pro'
END as Grading
FROM x
To have to keep repeating a calculation in order to do it all in one query is a bit ugly:
SELECT
CASE
WHEN SUM(Points) / DATEDIFF(day, MIN(GameStart), MAX(GameEnd)) < 100 THEN 'Newbie'
WHEN SUM(Points) / DATEDIFF(day, MIN(GameStart), MAX(GameEnd)) < 200 THEN 'Seasoned'
WHEN SUM(Points) / DATEDIFF(day, MIN(GameStart), MAX(GameEnd)) < 300 THEN 'Advanced'
ELSE 'Pro'
END as Grading
FROM
Games
GROUP BY PlayerId
And indeed because a GROUP BY is evaluated after a WHERE, if you want to use the result of a group by in a where you must do it as a "sub query that groups"/"outer query that wheres" pair
You can directly compare the concatenated value in the where clause like so:
CONCAT(umFirstName.meta_value, " ", umLastName.meta_value) LIKE '%abc%'
SELECT
u.ID AS id,
CONCAT(umFirstName.meta_value, " ", umLastName.meta_value) AS name,
u.user_email AS email,
umChatStatus.meta_value AS chatStatus,
umCallStatus.meta_value AS callStatus,
umRef.meta_value AS reference
FROM wp_users AS u
LEFT JOIN wp_usermeta AS um ON u.ID = um.user_id
LEFT JOIN wp_usermeta AS umFirstName ON u.ID = umFirstName.user_id AND
umFirstName.meta_key = "_ctbFirstName"
LEFT JOIN wp_usermeta AS umLastName ON u.ID = umLastName.user_id AND
umLastName.meta_key = "_ctbLastName"
LEFT JOIN wp_usermeta AS umChatStatus
ON u.ID = umChatStatus.user_id AND umChatStatus.meta_key = "_ctbChatSessionStatus"
LEFT JOIN wp_usermeta AS umCallStatus
ON u.ID = umCallStatus.user_id AND umCallStatus.meta_key = "_ctbCallSessionStatus"
LEFT JOIN wp_usermeta AS umRef ON u.ID = umRef.user_id AND umRef.meta_key = "_ctbRef"
WHERE um.meta_key = "wp_capabilities"
AND um.meta_value IN ('a:1:{s:8:"employee ";b:1;}')
AND u.id LIKE '%%'
OR CONCAT(umFirstName.meta_value, " ", umLastName.meta_value) LIKE '%%'
OR u.user_email LIKE '%%'
OR umChatStatus.meta_value LIKE '%%'
OR umCallStatus.meta_value LIKE '%%'
OR umRef.meta_value LIKE'%%'
ORDER BY id DESC
LIMIT 0, 20

Snowflake unsupported subquery when using function

This is the function I created:
CREATE OR REPLACE FUNCTION NS_REPORTS.AP."COUPA_GET_EXCH_RATE"("from_curr_id" NUMBER(38,0), "to_curr_id" NUMBER(38,0), "date" DATE)
RETURNS FLOAT
LANGUAGE SQL
AS '
SELECT
COALESCE((
SELECT
RATE
FROM
(
SELECT
ROW_NUMBER() OVER (PARTITION BY DATE(RATE_DATE) ORDER BY RATE_DATE DESC) ROW_NUM
, RATE
FROM
CONNECTORS.COUPA.EXCHANGE_RATE
WHERE
FROM_CURRENCY_ID = from_curr_id
AND TO_CURRENCY_ID = to_curr_id
AND DATE(RATE_DATE) = date
) R
WHERE
ROW_NUM = 1
), 1)
';
I'm using the ROW_NUMBER function because the RATE_DATE field is actually datetime and so there are multiple records per date.
When I call the function by itself, it works fine. However, when I try to use it in a view, I get the unsupported subquery type error. The view works fine without it. Can anyone think of what I can do to either fix the error or work around it by rewriting the query?
EDIT 1: View code and exact error message
CREATE OR REPLACE VIEW COUPA_REQUISITION
AS
SELECT
RH.ID REQ_NUM
, RL.LINE_NUM REQ_LINE_NUM
, OH.PO_NUMBER
, REPLACE(REPLACE(OH.CUSTOM_FIELDS:"legacy-po-number", '"', ''), '.0', '') LEGACY_PO_NUMBER
, S."NAME" SUPPLIER
, OH.STATUS
, UR.FULLNAME REQUESTED_BY
, UC.FULLNAME CREATED_BY
, OL.RECEIVED
, DATE(RH.SUBMITTED_AT) ORDER_DATE
, DATE(RH.NEED_BY_DATE) NEEDED_BY_DATE
, RL."DESCRIPTION" ITEM
, CAST(NULL AS VARCHAR) CHART_OF_ACCOUNTS
, REPLACE(OH.CUSTOM_FIELDS:"purchase-type", '"', '') PURCHASE_TYPE
, COM."NAME" COMMODITY
, ACT.NS_SUB_NAME SUBSIDIARY
, ACT.NS_ACCT_NAME_FULL "ACCOUNT"
, ACT.NS_DEPT_NAME_FULL DEPARTMENT
, ACT.NS_L3_DEPT_NAME L3_DEPARTMENT
, ACT.NS_LOC_NAME "LOCATION"
, RL.QUANTITY QTY
, OL.LINE_NUM ORDER_LINE_NUM
, RL.TOTAL * NS_REPORTS.AP.COUPA_GET_EXCH_RATE(RL.CURRENCY_ID, 1, DATE(RH.SUBMITTED_AT)) LINE_TOTAL
, RL.TOTAL - OL.INVOICED UNINVOICED_AMOUNT
, OL.INVOICED INVOICED_TOTAL
, RLSUM.TOTAL TOTAL
, REPLACE(IL.CUSTOM_FIELDS:"amortization-schedule"."name", '"', '') AMORTIZATION_SCHEDULE
, CASE WHEN COALESCE(IL.CUSTOM_FIELDS:"amortization-start-date", '') <> '' THEN DATE(REPLACE(IL.CUSTOM_FIELDS:"amortization-start-date", '"', '')) ELSE NULL END AMORTIZATION_START_DATE
, CASE WHEN COALESCE(IL.CUSTOM_FIELDS:"amortization-end-date", '') <> '' THEN DATE(REPLACE(IL.CUSTOM_FIELDS:"amortization-end-date", '"', '')) ELSE NULL END AMORTIZATION_END_DATE
, CASE WHEN COALESCE(OH.CUSTOM_FIELDS:"contract-start-date", '') <> '' THEN DATE(REPLACE(OH.CUSTOM_FIELDS:"contract-start-date", '"', '')) ELSE NULL END CONTRACT_START_DATE
, CASE WHEN COALESCE(OH.CUSTOM_FIELDS:"contract-end-date", '') <> '' THEN DATE(REPLACE(OH.CUSTOM_FIELDS:"contract-end-date", '"', '')) ELSE NULL END CONTRACT_END_DATE
FROM
CONNECTORS.COUPA.REQUISITION_HEADER RH
JOIN CONNECTORS.COUPA.REQUISITION_LINE RL ON RL.REQUISITION_HEADER_ID = RH.ID
JOIN NS_REPORTS.AP.COUPA_ACCOUNT ACT ON ACT.COUPA_ACCT_ID = RL.ACCOUNT_ID
JOIN CONNECTORS.COUPA."USER" UR ON UR.ID = RH.REQUESTED_BY_ID
JOIN CONNECTORS.COUPA."USER" UC ON UC.ID = RH.CREATED_BY_ID
JOIN (
SELECT
REQUISITION_HEADER_ID
, SUM(TOTAL) TOTAL
FROM
CONNECTORS.COUPA.REQUISITION_LINE
GROUP BY
REQUISITION_HEADER_ID
) RLSUM ON RLSUM.REQUISITION_HEADER_ID = RH.ID
LEFT JOIN CONNECTORS.COUPA.ORDER_LINE OL ON OL.ID = RL.ORDER_LINE_ID
LEFT JOIN CONNECTORS.COUPA.ORDER_HEADER OH ON OH.ID = OL.ORDER_HEADER_ID
LEFT JOIN CONNECTORS.COUPA.COMMODITY COM ON COM.ID = OL.COMMODITY_ID
LEFT JOIN CONNECTORS.COUPA.SUPPLIER S ON S.ID = OH.SUPPLIER_ID
LEFT JOIN CONNECTORS.COUPA.INVOICE_LINE IL ON IL.ORDER_LINE_ID = OL.ID
Error message:
SQL Error [2031] [42601]: SQL compilation error:
Unsupported subquery type cannot be evaluated
The error is a correlated subquery and the are not supported (beyond some tiny toy examples)
But the basic form is
SELECT a.a
(select b.b from b where b.a = a.a order by b.y limit 1)
FROM a;
in effect for each row, a sub-query is run on another table to get a value. There are many tricks done in other DB's to make this "work" but in effect there is work done on each row. Snowflake does not types of for each row operations.
The good news is there are other patterns that are effectively the same, that snowflake does support, the two patterns are really the same use a CTE or join to a sub-select which is the same thing.
so the above becomes:
WITH subquery AS (
SELECT b.a, b.b FROM b
QUALIFY row_number() over (partition by b.a order by b.y) = 1
)
SELECT a.a
sq.b
FROM a
JOIN subquery AS sq
ON sq.a = a.a
So we first process/shape "all records" from the other/sub table, and we only keep the rows that have the count/shape we want, and then join to that result. The is very parallelizable, so performs well. The reason Snowflake does not auto translate a sub-query for you, is it rather easy to get it wrong, and they presently are spending there development efforts working on features that do not exist at all, etc etc, and it can be rewritten by you, given you understand your model.
What if you move this to the FROM clause? I would phrase this as:
SELECT COALESCE(MAX(er.rate), 1)
FROM (SELECT er.*
FROM CONNECTORS.COUPA.EXCHANGE_RATE er
WHERE er.FROM_CURRENCY_ID = in_from_curr_id AND
er.TO_CURRENCY_ID = in_to_curr_id AND
DATE(er.RATE_DATE) = in_date
ORDER BY RATE_DATE DESC
LIMIT 1
) er;
Notice that I changed the names of the parameters so they are more obviously input parameters.

Using the results of a SQL query as parameters for a second one

Our SQL developer put together the following query to basically pull a list of any employee who has logged into our system today. This query works perfectly and will spit out a list of names. What I need to do is take the list of names it spits out and then use those in a new query to change a column on a different table for each of those names.
select distinct(t.CC_FullName) as Employee,
t.CC_Supervisor as Supervisor,
t.StaffCimID
from (
select s.*,
r.CC_FullName,
r.CC_Supervisor,
r.StaffCimID
from (
select AgentFirstName + ' ' + AgentLastName as AgentName,
Agent
from pia.dbo.Five9IntraDayExtract with(nolock)
group by AgentFirstName + ' ' + AgentLastName,
Agent
) s
inner join pia.dbo.StaffInformationNew r with(nolock)
ON CASE
WHEN s.Agent LIKE '%_manual' AND s.Agent = r.Five9Name_MTM THEN 1
WHEN s.Agent NOT LIKE '%_manual' AND s.Agent = r.Five9Name THEN 1
ELSE 0
END = 1
and r.EndDate is null
) t
where t.CC_FullName is not null
and t.StaffCimID is not null
order by t.CC_FullName, t.CC_Supervisor
so basically after that runs I get a list with three columns. I need to take the name column and basically do the following:
Update Attendance Set Seated = '1' where name = 'John Doe'
I need to do that for every result from the initial query. What's the best way to do that?
Add that to the top of your query...
Update Attendance
Set Seated = '1'
where name in
(select t.CC_FullName from (
select s.*,
r.CC_FullName,
r.CC_Supervisor,
r.StaffCimID
from (
select AgentFirstName + ' ' + AgentLastName as AgentName,
Agent
from pia.dbo.Five9IntraDayExtract with(nolock)
group by AgentFirstName + ' ' + AgentLastName,
Agent
) s
inner join pia.dbo.StaffInformationNew r with(nolock)
ON CASE
WHEN s.Agent LIKE '%_manual' AND s.Agent = r.Five9Name_MTM THEN 1
WHEN s.Agent NOT LIKE '%_manual' AND s.Agent = r.Five9Name THEN 1
ELSE 0
END = 1
and r.EndDate is null
) t
where t.CC_FullName is not null
and t.StaffCimID is not null)

Not able to apply join in sql query

i want to add the join "JOIN {User}
ON {Deck}.[CreatedBy] = {User}.[Id]" in following query. I tried many combination but not succeeded. i want to fetch Name from User table
SELECT #CampaignQueryFilterString AS [Selected],
{Deck}.[Id], {Deck}.[Name],
{User}.[Name],
{Deck}.[TableOfContentId], {Deck}.[CreatedBy],
{Deck}.[LastModifiedOn], {Deck}.[ExpiryDate],s1.[Count]
FROM {Deck}
JOIN
(
SELECT {Deck}.[Id],
LISTAGG( {TagValue}.[Id], ',' ) WITHIN GROUP (ORDER BY {TagValue}.[TagCategoryId] ) AS Tags
FROM {Deck}
JOIN {AssociatedDeckTags}
ON {AssociatedDeckTags}.[DeckId] = {Deck}.[Id]
JOIN {TagValue}
ON {AssociatedDeckTags}.[TagValueId] = {TagValue}.[Id]
WHERE {Deck}.[IsPublished] = 1
AND {Deck}.[IsActive] = 1 AND {Deck}.[ReplacedByDeckId] IS NULL
AND {Deck}.[TableOfContentId] IN #TableOfContentIdFilterString
AND {Deck}.[ContentFileTypeId] IN #AllowedContentType
AND {Deck}.[ExpiryDate] > SYSDATE
GROUP BY {Deck}.[Id]
) DeckView
ON {Deck}.[Id] = DeckView.Id
JOIN(
SELECT COUNT(*) AS [Count], {DeckGroup}.[DeckId] AS [S1DeckId]
FROM {DeckGroup}
JOIN {Slide} ON {Slide}.[DeckGroupId] = {DeckGroup}.[Id]
GROUP BY {DeckGroup}.[DeckId]
) s1 ON s1.[S1DeckId] = {Deck}.[Id]
#RegexString
#SearchFilter
#CreatedBy
GROUP BY
{Deck}.[Id], {Deck}.[Name], {Deck}.[TableOfContentId],
{Deck}.[CreatedOn], {Deck}.[CreatedBy],
{Deck}.[LastModifiedOn], {Deck}.[ExpiryDate],
{Deck}.[NumOfPreviews], {Deck}.[NumOfDownloads],s1.[Count]
ORDER BY #Orderby
Looks like simply join, please try the below query (using your notation). I added left join and in group by clause - {User}.[Name]. Optionally you can use some aggregating function for {User}.[Name] - max(), listagg() and remove it from group by clause.
SELECT #CampaignQueryFilterString AS [Selected],
{Deck}.[Id], {Deck}.[Name], {User}.[Name], {Deck}.[TableOfContentId],
{Deck}.[CreatedBy], {Deck}.[LastModifiedOn], {Deck}.[ExpiryDate], s1.[Count]
FROM {Deck}
JOIN DeckView ON {Deck}.[Id] = DeckView.Id -- subquery1
JOIN s1 ON s1.[S1DeckId] = {Deck}.[Id] -- subquery2
LEFT JOIN {User} ON {Deck}.[CreatedBy] = {User}.[Id] -- <-- add join here
#RegexString
#SearchFilter
#CreatedBy
GROUP BY
{Deck}.[Id], {Deck}.[Name], {User}.[Name], -- <-- add column here
{Deck}.[TableOfContentId], {Deck}.[CreatedOn],
{Deck}.[CreatedBy], {Deck}.[LastModifiedOn],
{Deck}.[ExpiryDate], {Deck}.[NumOfPreviews],
{Deck}.[NumOfDownloads], s1.[Count]
ORDER BY #Orderby
You didn't show your tries, so we don't know if there was an error or undesired result. With this form of question that is all I can help. Also USER is one of Oracle Reserved Words, it's better to avoid using it as alias, variable name etc.

missing field in nested SQL statement in ms access 2010

The following MS Access 2010 query only outputs values for FirstName, HomePhone, and ClientNumber. It is not outputting any values for LastName.
Can anyone show me how to change it so that it outputs values for LastName also?
SELECT
ActiveCustomers.FirstName
, ActiveCustomers.LastName
, tblClientAddress.HomePhone
, ActiveCustomers.ClientNumber
FROM (
SELECT
Clients.ClientNumber
, Clients.FirstName
, Clients.LastName (
SELECT COUNT(ReferralDate) FROM IntakeTable
WHERE Clients.ClientNumber = IntakeTable.ClientNumber
AND Len(ReferralDate & '') > 0
) AS IntakeCount
, (
SELECT COUNT(ExitDate)
FROM ExitTable
WHERE Clients.ClientNumber = ExitTable.ClientNumber
AND Len(ExitDate & '') > 0
) AS ExitCount
FROM Clients
) AS ActiveCustomers
INNER JOIN tblClientAddress
ON ActiveCustomers.ClientNumber = tblClientAddress.ClientNumber
WHERE ActiveCustomers.IntakeCount > [ExitCount]
AND tblClientAddress.CurrentResidence = True;
You appear to be missing a comma after Clients.LastName. Try:
SELECT ActiveCustomers.FirstName, ActiveCustomers.LastName, tblClientAddress.HomePhone, ActiveCustomers.ClientNumber
FROM
(SELECT Clients.ClientNumber,
Clients.FirstName,
Clients.LastName,
(SELECT COUNT(ReferralDate) FROM IntakeTable WHERE Clients.ClientNumber = IntakeTable.ClientNumber AND Len(ReferralDate & '') > 0) AS IntakeCount,
(SELECT COUNT(ExitDate) FROM ExitTable WHERE Clients.ClientNumber = ExitTable.ClientNumber AND Len(ExitDate & '') > 0) AS ExitCount
FROM Clients) AS ActiveCustomers
INNER JOIN tblClientAddress ON ActiveCustomers.ClientNumber = tblClientAddress.ClientNumber
WHERE (((ActiveCustomers.IntakeCount)>[ExitCount]) AND
((tblClientAddress.CurrentResidence)=True));
EDIT:
It seems likely that:
You have a many-to-one (or one-to-many) relationship between Clients and tblClientAddress, and you have two records on the "many" side. If you are getting duplicate records, you could add a DISTINCT or a GROUP BY,
And/Or:
That the (SELECT COUNT( subqueries are somehow messing up their parent query, and need to be modified so that they can go into their parent query's FROM clause with an Inner Join, e.g.:
(SELECT ClientNumber, COUNT(ReferralDate) as IntakeCount FROM IntakeTable WHERE Len(ReferralDate & '') > 0 GROUP BY ClientNumber) AS qryIntakeCount