Defining new variable from Subquery - Only scalar expressions are allowed. (SQL Server) - sql

I'm trying to add a column [Missed 2x] to an existing table that indicates whether the Subject has had two consecutive missed diaries. The value is "Missed 2x" if the most recent 2 diaries are missed, and NULL otherwise. I wrote a select statement (within the code below) that successfully pulls the IDs who meet this criteria. When I created a User-Defined Function to cross-check the table and assign the value, it was untenable, as the function is recalculated for every ID every time that table is queried and took forever.
I attempted to assign the value via Alter Table by seeing if the ID of the existing table is in the Subset table. I figured this should save resources since the subset table is defined once, and the Alter statement simply checks if each ID is in the subset. Then I became aware that I can't do this with Alter Table as I get the error Subqueries are not allowed in this context. Only scalar expressions are allowed.
What is the most efficient alternative?
ALTER TABLE [R3008_Subjchar] add [Missed 2x] as
case when [Subject ID] in
(
select
[Subject ID]
from(
select distinct
[Subject ID]
, [Questionnaire Name]
, [Task Date]
, [Is Completed]
, dense_rank () over (Partition by [Subject ID], [Questionnaire Name] order by [Task Date] desc) as recency
from dbo.R3008_Questionnaire
) r
where recency <=2
group by [Subject ID]
having count(case when [Is Completed] = 'no' and [Questionnaire Name] = 'FLU-PRO Questionnaire' then [Is Completed] end) = 2
)
then 'Missed 2x' end

You can't use a subquery in a computed column; it may only access the data that is on the current row, not other rows.
I don't think that storing such information is a good idea. Instead, you can create a view; lag() comes handy to implement the logic you want:
create view v_r3008_questionnaire
select q.*,
case when [Is Completed] = 'no'
and lag([Is Completed]) over(partition by [Subject ID], [Questionnaire Name] order by [Task Date]) = 'no'
then 'Missed 2x'
end as [Missed 2x]
from dbo.r3008_questionnaire
For each "failed" row, this check if the previous status for the same subject and questionnaire is failed as well, and sets the flag in that case.

Related

SQL Query returning more rows when I add in a specific column from table than without

Feeling a bit confused here, I have a query running against SQL Server where I am trying to return a single row per trans_id and action number (they may be repeated). The trans column would be different in the repeated rows so I only ever want to return the highest (max value) of the trans column to give me the single row per trans_id and action number.
This seems to do the trick:
SELECT DT.trans_id,
MAX(DT.trans),
DA.ACTION_NO,
DT.[Title] AS [Case Title],
DA.[Description] AS [Action Description],
DA.ACTION_TIME_LIMIT AS [Action Deadline],
DA.Performed AS [Action Perfomed]
FROM synergi.stg_D_TRANS DT
INNER JOIN EQDW_Stg.synergi.stg_D_ACTION DA ON DA.TRANS = (SELECT MAX(TRANS)FROM synergi.stg_D_TRANS WHERE trans_id = DT.TRANS_ID)
WHERE DT.TRANS_ID != 0
GROUP BY DT.TRANS_ID,
DA.ACTION_NO,
DT.TITLE,
DA.DESCRIPTION,
DA.PERFORMED,
DA.ACTION_TIME_LIMIT;
However, when I add in this specific column, DT.TRANS_DATE, I get an additional 18 rows because it is returning one of the trans_id with 2 different trans numbers instead of just the rows with the max.
Why would adding in the date column affect this when I have numerous other columns from the same table that adding/removing don't seem to change the result at all.
SELECT DT.trans_id,
MAX(DT.trans),
DA.ACTION_NO,
DT.[Title] AS [Case Title],
DA.[Description] AS [Action Description],
DA.ACTION_TIME_LIMIT AS [Action Deadline],
DA.Performed AS [Action Perfomed],
DT.TRANS_DATE
FROM synergi.stg_D_TRANS DT
INNER JOIN EQDW_Stg.synergi.stg_D_ACTION DA ON DA.TRANS = (SELECT MAX(TRANS)FROM synergi.stg_D_TRANS WHERE trans_id = DT.TRANS_ID)
WHERE DT.TRANS_ID != 0
GROUP BY DT.TRANS_ID,
DA.ACTION_NO,
DT.TITLE,
DA.DESCRIPTION,
DA.PERFORMED,
DA.ACTION_TIME_LIMIT,
DT.TRANS_DATE;

LOOP and COUNT in a SELECT statement SQL SERVER

I have a view with these columns
and i want to extract this data
i am doing it in SQL Server manually in several steps and i want to automate it so that i can run a select statement directly from a macro and save it in excel file.
Here is what i am doing
select distinct
CASE
WHEN Userid ='jsolar' THEN 'Jack Solar'
WHEN Userid ='jkrcmarikova' THEN 'Jana Krcmarikova'
WHEN Userid ='lfialova' THEN 'lucia fialova'
WHEN Userid ='zsnopkova' THEN 'zuzana snopkova'
END AS [User Name]
, Region
from [SC].[vw_X86_Orders_By_UserID_GAMMA]
order by Region, [User Name]
Then i copy the result in excel file and run other queries for each user
SELECT Count ( DISTINCT [Order Number])
FROM [SC].[vw_X86_Orders_By_UserID_GAMMA]
where Userid LIKE 'jsolar'
AND Region LIKE 'CENTRAL'
and [Order Entry Date] = '2016-10-27'
i save this result in number of distinct order number. Then i run this query
SELECT Count ( DISTINCT CONCAT ([Order Number], [Line No]))
FROM [SC].[vw_X86_Orders_By_UserID_GAMMA]
where Userid LIKE 'jsolar'
AND Region LIKE 'CENTRAL'
and [Order Entry Date] = '2016-10-27'
I save this result in number of distinct order number concatenated with line no. And i repeat the same for each user
At the end it should be something like this in Excel
Is there a way how to do this in one select statement to loop each user and count for all users at the same time ? Thank you very much.
I really don't think you need a "LOOP". SQL operates best in set based operations returning recordsets with many rows. So we need to treat [SC].[vw_X86_Orders_By_UserID_GAMMA] as an entire set and simply update the case statement to translate all users names (assuming you have to have them, or you could do a vlookup on the userID in excel after the fact)
I think what you're really after is the count(distinct column) in combination with a group by on userID and region.
Based on comments I think you would need to amend the case statements in the select and group by to contain the translation for all the users.
I think there's too many unknowns to provide a 100% correct response but here's a shot across the bow..
SELECT CASE WHEN Userid ='jsolar' THEN 'Jack Solar'
WHEN Userid ='jkrcmarikova' THEN 'Jana Krcmarikova'
WHEN Userid ='******' THEN '**** *******'
WHEN Userid ='****' THEN '***** ****' END AS [User Name]
, Region
, count(distinct [Order Number]) as cntDistinctOrders
, count(Distinct concat([order Number], [Line No]) as cntDistinctOrderLines
FROM [SC].[vw_X86_Orders_By_UserID_GAMMA]
WHERE [Order Entry Date] = '2016-10-27'
-- and Region = 'CENTRAL' don't think you need this the group by handles same names in different regions keeping them distinct and counts seperate.
GROUP BY CASE WHEN Userid ='jsolar' THEN 'Jack Solar'
WHEN Userid ='jkrcmarikova' THEN 'Jana Krcmarikova'
WHEN Userid ='******' THEN '**** *******'
WHEN Userid ='****' THEN '***** ****'
END
, Region
ORDER BY [User Name], Region
To put this in plain English...
You want all the usernames and regions for each user in the [SC].[vw_X86_Orders_By_UserID_GAMMA] schema.table showing the distinct count of orders and order lines for a specific date.
If you can use a Vlookup in excel for the names you could getaway without the case statements and all that extra code..
SELECT UserId [User Name]
, Region
, count(distinct [Order Number]) as cntDistinctOrders
, count(Distinct concat([order Number], [Line No]) as cntDistinctOrderLines
FROM [SC].[vw_X86_Orders_By_UserID_GAMMA]
WHERE [Order Entry Date] = '2016-10-27'
-- and Region = 'CENTRAL' don't think you need this the group by handles same names in different regions keeping them distinct and counts seperate.
GROUP BY CASE UserID
, Region
ORDER BY [User Name], Region
--note because the group by executes before the select statement, we have to group by the USERID and not the alias name of [User name]

Asking to enter a parameter value that already exists

I have a three column table of price breaks called "FPB" that looks like this:
[Part Number] [Quantity] [Price]
AAA-AAAA     100   1.23
AAA-AAAA     200   1.15
BBB-BBBB     100   5.60
CCC-CCCC      500   3.21
....
Where each part number has multiple entries in multiple rows.
I'm trying to reorganize the table to look more like this
[Part Number] [Quantity1] [Price 1] [Quantity 2] [Price 2] [Quantity 3....
AAA-AAAA      100   1.23    200    1.15   ....
BBB-BBBB      100   5.60     ...
CCC-CCCC       500   3.21    ...
...
Where each part number has all its entries combined into one row. The first quantity column should have the lowest available quantity, the second should have the second smallest etc. I am trying to do this by first creating a 1-column table with just the unique part numbers using GROUP BY, and then creating more tables for each column that has the information I want in that column, and then joining it by Part Number. The problem comes when calculating the second smallest quantity for each type, done in the second to last section.
SELECT PNs.[Part Number], Q1T.Q1, P1T.Price, Q2T.Q2
FROM
(SELECT
[Part Number]
FROM FPB
GROUP BY [Part Number]
) AS PNs,
(SELECT
[Part Number],
MIN(Quantity) AS Q1
FROM FPB
GROUP BY [Part Number]
) AS Q1T,
(SELECT
*
FROM FPB
) AS P1T,
(SELECT
[Part Number],
MIN(IIF(Quantity>Q1T.Q1,Quantity)) AS Q2
FROM FPB
GROUP BY [Part Number]
) AS Q2T
WHERE
PNs.[Part Number] = Q1T.[Part Number]
AND P1T.[Part Number] = PNs.[Part Number]
AND P1T.Quantity = Q1T.Q1
AND Q2T.[Part Number] = PNs.[Part Number]
When I run this query, it asks me to enter a parameter value for Q1T.Q1, even though it already exists. If I remove the code section for Q2T, as well as any references to Q2, it will work without a problem, and it won't ask about a value for the other instances of Q1T.Q1. Why doesn't Q1T.Q1 have a value just for that section, and how can I fix it? As a side note, I'm using the SQL features of a program called PHPRunner, and its client doesn't support UPDATE/DELETE/INSERT/CREATE queries, UNION, and DISTINCT.
You're looking for something like this.
select
p1.PartNumber,
ifnull(max(p2.Quantity), 0) + 1 as LowerQuantity,
p1.Quantity as UpperQuantity,
p1.Price,
count(p2.PartNumber) + 1 as PriceTier
from
FPB p1 left outer join FPB p2
on p2.PartNumber = p1.PartNumber and p2.Quantity < p1.Quantity
From there it's easy to pivot in order to insert into a new table:
into into NewFPB (PartNumber, Quantity1, Price1, Quantity2, Price2, ...)
select
PartNumber,
min(switch(PriceTier = 1, UpperQuantity)) as Quantity1,
min(switch(PriceTier = 2, UpperQuantity)) as Quantity2, ...
min(switch(PriceTier = 1, Price)) as Price1,
min(switch(PriceTier = 2, Price)) as Price2, ...
from (
select
p1.PartNumber,
ifnull(max(p2.Quantity), 0) + 1 as LowerQuantity,
p1.Quantity as UpperQuantity,
p1.Price,
count(p2.PartNumber) + 1 as PriceTier
from
FPB p1 left outer join FPB p2
on p2.PartNumber = p1.PartNumber and p2.Quantity < p1.Quantity
) data
You might have to tweak it a little bit for Access to accept it. But the core ideas are there.
The query you call is incorrect.
Q1T is inner select statement , and in Q2T (other inner select statement) , you can't use any field from Q1T
The SQL Server raise error: Incorrect syntax near ')'.
To overcome this limitation , you should use Common Table Expressions CTE
for PNs, Q1T, P1T, Q2T
CTE is like dynamic view.
It's a new feature since sql 2008 and It's a very powerful.
review: https://technet.microsoft.com/en-us/library/ms190766(v=sql.105).aspx
Try to Draw a relational data model for these four CTE to be sure that a relation exist between them based on your where conditions.
I think the logic in this query may raise runtime error during execution:
e.g. The multi-part identifier "Q1T.Q1" could not be bound.
Edit:
For Ms-Access you can create four queries for: PNs, Q1T, P1T, Q2T every one is in a separate query, and the fifth query join these queries and add where conditions.
In this case you will not get any syntax error. and will get Data model with relation free :) .
As per your question, by the time you define the derived table Q2T, Q1T is still an invalid object. You need to try to work around this issue.
EDIT:
Suppose you only got 2-level columns to handle, the code is listed below, i tested it. It works well.
select q5.*,q3.quantity, q3.price
from
(select *
from FPB as Q1
where 0 = (select count(distinct(quantity)) from FPB as Q2 where Q2.quantity < Q1.quantity AND Q2.[part number] = Q1.[part number])) as Q5
,
(
select distinct(temp.[part number]),Q2.quantity, Q2.price from FPB as temp
left join
(select *
from FPB as Q4
where 1 = (select count(distinct(quantity)) from #test as Q2 where Q2.quantity < Q4.quantity AND Q2.[PART NUMBER] = Q4.[PART NUMBER])) as Q2
on temp.[PART NUMBER] = Q2.[PART NUMBER]
) as Q3
where Q5.[PART NUMBER] = Q3.[PART NUMBER]

SQL Server 2012 / Add row_number over two queries?

I have a question about adding a row number over 2 queries.
My query is:
SELECT
'telxm001001' AS Node,
'1' AS [Speed Dialing],
'0' AS [Spd DI Numbers by Range],
NULL as 'Speed Dialing No.',
REPLACE(TelefonGeschaeft, '+', '00') AS [Call Number],
Nachname AS [Directory Name],
Vorname AS [Directory First Name]
FROM
dbo.MaData
WHERE
(TelefonGeschaeft LIKE '+%')
UNION ALL
SELECT
'telxm001001' AS Node,
'1' AS [Speed Dialing],
'0' AS [Spd DI Numbers by Range],
ROW_NUMBER() OVER (ORDER BY Nachname) AS 'Speed Dialing No.',
REPLACE(MobiltelefonGeschaeft, '+', '00') AS [Call Number],
Nachname AS [Directory Name],
Vorname AS [Directory First Name]
FROM
dbo.MaData
WHERE
(MobiltelefonGeschaeft LIKE '+%')
I have a SQL Server table with 1400 entries. The 2 queries brings me the right results but the row numbers are not correct because the numerations Begins at 1 when the second query starts. So in my query result i have a numeration from 1 to 680 and then the numeration Begins at 1 when the second query starts. Is there a way to add a row numbering after the two queries finished so the numeration is from 1 to 1400?
Best regards
switzly
Apply a ROW_NUMBER ordering over a derived query; supply a discriminator (e.g. queryOrder) through the individual queries to keep the relevant results grouped.
SELECT ROW_NUMBER() OVER (ORDER BY queryOrder, [Directory Name]) AS number
FROM (
SELECT 1 AS queryOrder, [Directory Name] ..
UNION ALL
SELECT 2 AS queryOrder, [Directory Name] ..
) j
Before jump into too techie in to this query, do you want to have the row number for both the queries?
If yes, why are you putting NULL in the first query?
If you want to have row number for both the queries, use it on both the queries.
Otherwise, try put them into another query as below:
select
ROW_NUMBER over ..., Node, [Speed Dialing], ....
from
(<actual query here>) as temp1;

Complex SQL query excluding results from other SQL queries

This question is a continuation from this question
There is a slight change to the database structure however (as I over simplified slightly)
I have a database with data columns as follows:
Key, Instance, User ID, Day, Size, Instance Type
Key - This is the primary key.
Instance - This is a descriptor of the specific instance (this will be unique).
User ID - This will refer to 1 of a number of users where the number will be less than the number of entries in this table.
Day - This is the day the specific user created this instance. It will be one of either Day 1 or Day 2.
Size - This is the size of the data stored.
Instance Type - There are several instance types An instance, itself, will be one of these instance types.
Now in my previous question I was building a nested SQL query to find a distinct users who has instance on day 1 and day 2 and in this case with a specific instance type.
Now I have 2 sets of these queries.
What I would now like to do is a 3rd query and return the database where the User ID does not exist in either of the other queries.
So far I have set up a query but it is REALLY slow (Something to do with the <> comparator in the On statement) and I'm not even 100% sure it does exactly what I want.
This is my SQL statement so far:
Select Max( Table.Key ) as Key,
Max( Table.Instance ) as Instance,
Table.[User ID],
Max( Table.Day ) as Day,
Max( Table.Size ) as Size,
Max( Table.[Instance Type] ) as [Instance Type]
from (((Table
inner join (Select top 90 Max( Table.Key ) as Key,
Max( Table.Instance ) as Instance,
Table.[User ID],
Max( Table.Day ) as Day,
Max( Table.Size ) as Size,
Max( Table.[Instance Type] ) as [Instance Type]
from Table
where Table.[Instance Type]="type1" and
Table.[Day]=1 and
1=1
group by Table.[User ID]) as t2
on Table.[User ID]<>t2.[User ID])
inner join (Select top 90 Max( Table.Key ) as Key,
Max( Table.Instance ) as Instance,
Table.[User ID],
Max( Table.Day ) as Day,
Max( Table.Size ) as Size,
Max( Table.[Instance Type] ) as [Instance Type]
from Table
where Table.[Instance Type]="type1" and
Table.[Day]=2 and
1=1
group by Table.[User ID]) as t3
on Table.[User ID]<>t3.[User ID])
inner join (Select Table.[User ID]
from Table
where 1=1 ) as t4
on Table.[User ID]=t4.[User ID])
where Table.[Instance Type]="type1"
group by Table.[User ID];
Any help or advice on how to get what I'm after would be massively appreciated!
It might make things easier for performance tuning to start with chunking this up as temporary tables (in MS-Access, i guess 'views' or 'make-tables', particularly as your logic seems overly complex (and therefore difficult to maintain and debug!):
Part 1 of your question: "Now in my previous question I was building a nested SQL query to find a distinct users who has instance on day 1 and day 2 and in this case with a specific instance type."
Why don't you first use a 'temp table/make table' or 'view' or whatever (depending on how you're implementing, by first getting a distinct list of userid's with the day.
SELECT DISTINCT Table.UserID, Table.Day
INTO #DistinctListOfUserIDsWithDays /* Not sure of exact syntax in access! */
FROM Table
WHERE Table.Day = 1
OR Table.Day = 2
And then you can get all users that have data for both days, which solves your first part easily, by aggregating the results of the view/query above and using a having clause:
SELECT Table.UserID, COUNT(*)
FROM #DistinctListOfUserIDsWithDays
HAVING COUNT(*) > 1
Now I have 2 sets of these queries.
re: Your new query, "What I would now like to do is a 3rd query and return the database where the User ID does not exist in either of the other queries", here's one simple solution, based on the original query/view above:
SELECT Table.UserID
FROM Table
WHERE UserID NOT IN (SELECT UserID FROM #DistinctListOfUserIDsWithDays)
You cold also outer join #DistinctListOfUserIDsWithDays with the Table and select only those UserID's that return a NULL on the #DistinctListOfUserIDsWithDays side of the query...