Using a scalar variable inside a CTE - sql

I am reviewing someone else's code but I've hit a wall. When I try to execute the provided script I get the following error:
Must declare the scalar variable "#userId".
I tried to remove the semicolon on line 2 just to try things but that give me the following error:
Incorrect syntax near the keyword 'with'. If this statement is a common table expression, an xmlnamespaces clause or a change tracking context clause, the previous statement must be terminated with a semicolon.
I'm very confused by this because this exact piece of code works on machines of others, but not on mine. I know there are other ways to write this query but I need to get this to work. Is there any way to make the variable work as intended in this script without rewriting the whole thing?
I'm using Microsoft SQL Server 2019 (RTM-CU8) (KB4577194) - 15.0.4073.23 (X64) on Ubuntu 18.04.4 LTS.
DECLARE #userId int
SET #userId =:user_id;
WITH bidsplacedtotal AS (
SELECT amount, user_id, auction_id
FROM bids WHERE user_id = #userId
)
,bidsreceivedtotal AS (
SELECT amount, user_id, auction_id
FROM bids WHERE auction_id IN
(SELECT id FROM auctions WHERE user_id = #userId)
)
SELECT COUNT(amount) FROM bidsplacedtotal) AS placed_total
UNION
SELECT COUNT(amount) FROM bidsreceivedtotal) AS received_total

Try this code to see if it works:
DECLARE #userId int
SELECT #userId = 2091
;WITH bidsplacedtotal AS (
SELECT amount, user_id, auction_id
FROM bids WHERE user_id = #userId
)
,bidsreceivedtotal AS (
SELECT amount, user_id, auction_id
FROM bids WHERE auction_id IN
(SELECT id FROM auctions WHERE user_id = #userId)
)
SELECT COUNT(amount) as CountAmount FROM bidsplacedtotal) AS placed_total
UNION
SELECT COUNT(amount) as CountAmount FROM bidsreceivedtotal) AS received_total

Related

How to aggregate/concate strings with no duplicates in SQL Server 2019

I am very new to SQL Server and it stucks in one task related to the aggregation of data. I tried to put all information on the screen attached. Is there anyone that could support it? My current code is below, but it does not work (duplicates...). Many thanks in advance!
select distinct
material,
plant,
STRING_AGG (exceptions, ';' ),
STRING_AGG (preferential_country, ';' )
from grs
GROUP BY material, plant
Sorry, I misunderstood part of your question. This is a bit messy, but I created a function to remove the duplicates.
CREATE FUNCTION remove_duplicate (#str varchar(100))
RETURNS varchar(100) AS
BEGIN
DECLARE #result varchar(100)
SET #result = (SELECT STRING_AGG(ta.value,';') from(
SELECT DISTINCT value FROM STRING_SPLIT(#str ,';')
)as ta)
RETURN #result
END;
This is the query to create the output table where the exceptions are group together but there will be duplicates
SELECT distinct plant,
material,
CASE WHEN count( distinct(preferential_country)) > 1 THEN 'QU'
ELSE MAX(preferential_country)
END AS preferential_country,
STRING_AGG(exceptions,';') as exceptions
into new_table
FROM tableA
group by plant, material
order by plant
Lastly, you just need to use the function to remove the duplicates.
SELECT plant, material, dbo.remove_duplicate(exceptions) as exceptions from new_table
output:
plant material exceptions
plant_1 Material_1 EU01;EU02;EU03;EU05
plant_1 Material_2 EU01
plant_2 Material_1 NULL
I couldn't get it to work in db fiddle but it's working on SSMS
db fiddle

SQL Server list too long

I am trying to run this SQL statement:
select *
from table
where 1 = 1
and date >= '1/1/2020'
and id = any (**'list of 1300 items'**)
order by date asc;
The issue is that my list in the second and statement is actually over 1000 expressions, so it does not let me run this statement. Does anyone know a better way to do this? Basically, I have and ID that I want to locate in our database and the easiest way I know to do this is with a list but clearly mine is too long. I'm new to this so any insight would be greatly appreciated!
There are multiple ways to do that. For example, if your SQL server version is not old, you could use openJSON(). ie:
DECLARE #ids VARCHAR(MAX) = '[1,3,34,434,43]' -- your 1300+ ids
select *
from yourtable
where [date] >= '20200101'
and id IN (SELECT [value] FROM OPENJSON(#ids))
order by [date] asc;
You can think of string_split, if your SQL Server version is 2016 or later. Thanks to #Cetin Bazos for the basic script.
DECLARE #ids NVARCHAR(MAX) = '1,3,34,434,43' -- your 1300+ ids
select *
from yourtable
where [date] >= '20200101'
and id IN (SELECT [value] FROM STRING_SPLIT(#ids,','))
order by [date] asc;

QSqlQuery Not Executing When Using Table Variable

I am using Python 3 and PyQt 5 to execute a query that includes a table variable. My other queries work, but this specific one is causing me issues. The query is:
declare #Temp table
(
SKU varchar(25),
Lines int
)
insert into #Temp
SELECT convert(varchar, [Sku]) as [SKU]
,count([Order Number]) as [Lines]
from [Database].dbo.[Table Name]
GROUP BY [Sku]
ORDER BY [LINES]
Select RANK() OVER(Order by Lines Desc) / (Select Convert(float,Count(*)) from #Temp) as [CUM PERCENT SKU]
,sum(Lines) Over(Order by Lines Desc) / convert(float,sum(Lines) Over()) as [CUM PERCENT LINES]
from #Temp
Order By [Lines] DESC
I replaced the Database name and the Table name, but the rest of the text is the exact query.
Executing the above in SQL Server 2012 works perfectly. Is there a limitation to QSql that I don't know about?
Thank you in advance!
After a bit more research, it turns out that you need to use prepare() when you are trying to create a table (apparently even a temporary one).
I'm posting the answer in case anyone else has the same issue and doesn't feel like going through the C++ StackOverflow answers.
query = QSqlQuery()
query.prepare(*query text here*)
query.exec_()

PLSQL more than single row returned issue in ID field

I have an issue with the query below, in the main SELECT the value of
ENTITY_ID cannot be retrieved, as I'm using LIKE I get more than a single result back.
How can I overcome this?
If I place an inner SELECT such as:
(
SELECT
SEC_NN_SERVER_T.SRV_ID
FROM
SEC_NN_SERVER_T
WHERE
UPPER(SEC_NN_SERVER_T.SRV_NAME) LIKE UPPER('%gen%') ) AS ENTITY_ID,
I get the same error:
"ORA-01427: single-row subquery returns more than one row".
He is the full query:
SELECT DISTINCT
SEC_USER.USR_ID AS USR_ID,
SEC_USER.USR_FIRST_NAME AS USR_FIRST_NAME,
SEC_USER.USR_LAST_NAME AS USR_LAST_NAME,
SEC_USER_PRIV.ROLE_ID AS SYSTEM_ROLE_ID,
21 AS ENTITY_TYP_CODE,
(
SELECT
SEC_NN_SERVER_T.SRV_ID
FROM
SEC_NN_SERVER_T
WHERE
UPPER(SEC_NN_SERVER_T.SRV_NAME) LIKE UPPER('%gen%') ) AS ENTITY_ID
FROM
SEC_USER_PRIV,
SEC_USER
WHERE
SEC_USER.USR_ID = SEC_USER_PRIV.USR_ID
AND ((
SEC_USER_PRIV.ENTITY_TYP_CODE = 21
AND SEC_USER_PRIV.ENTITY_ID IN (
(
SELECT
SERVER_T.SRV_ID
FROM
SERVER_T
WHERE
UPPER(SERVER_T.SRV_NAME) LIKE UPPER('%gen%') ))))
Please assist thanks in advance.
By repeating the subquery from your where clause in your select you destroy the coupling between SEC_USER_PRIV.ENTITY_ID and the subquery. Subqueries in the SELECT part should always return only one value, because the select constructs the row to be returned. I expect your problem will be solved by simply including SEC_USER_PRIV.ENTITY_ID instead of the subquery.
What part of the error message do you not understand? Your subquery is returning more than one row. You can fix the error by using rownum or aggregation:
(SELECT MAX(SEC_NN_SERVER_T.SRV_ID)
FROM SEC_NN_SERVER_T
WHERE UPPER(SEC_NN_SERVER_T.SRV_NAME) LIKE UPPER('%gen%')
) as ENTITY_ID
or perhaps:
(SELECT LISTAGG(SEC_NN_SERVER_T.SRV_ID, ', ') WITHIN GROUP (ORDER BY SEC_NN_SERVER_T.SRV_ID)
FROM SEC_NN_SERVER_T
WHERE UPPER(SEC_NN_SERVER_T.SRV_NAME) LIKE UPPER('%gen%')
) as ENTITY_IDS
However, this might not be what you really want. You need to review the logic of what you are doing.
you can try the query below
SELECT DISTINCT
SEC_USER.USR_ID AS USR_ID,
SEC_USER.USR_FIRST_NAME AS USR_FIRST_NAME,
SEC_USER.USR_LAST_NAME AS USR_LAST_NAME,
SEC_USER_PRIV.ROLE_ID AS SYSTEM_ROLE_ID,
21 AS ENTITY_TYP_CODE,
SEC_NN_SERVER_T.SRV_ID AS ENTITY_ID
FROM SEC_USER_PRIV inner join
SEC_USER on SEC_USER.USR_ID = SEC_USER_PRIV.USR_ID inner join
SERVER_T on SEC_USER_PRIV.ENTITY_ID = SERVER_T.SRV_ID
and UPPER(SERVER_T.SRV_NAME) LIKE '%GEN%'
where SEC_USER_PRIV.ENTITY_TYP_CODE = 21
Looking at the comments on above answers, and guessing as it is not clear what you want to do, you might like to investigate cursors. A generic example below.
Declare
cursor c_test is
SELECT SEC_NN_SERVER_T.SRV_ID
FROM SEC_NN_SERVER_T
WHERE UPPER(SEC_NN_SERVER_T.SRV_NAME) LIKE UPPER('%gen%') ) AS ENTITY_ID
begin
for v_row in c_test loop
your logic for each ID here.
end loop;
end;

Paging SQL Server 2005 Results

How do I page results in SQL Server 2005?
I tried it in SQL Server 2000, but there was no reliable way to do this. I'm now wondering if SQL Server 2005 has any built in method?
What I mean by paging is, for example, if I list users by their username, I want to be able to only return the first 10 records, then the next 10 records and so on.
Any help would be much appreciated.
You can use the Row_Number() function.
Its used as follows:
SELECT Row_Number() OVER(ORDER BY UserName) As RowID, UserFirstName, UserLastName
FROM Users
From which it will yield a result set with a RowID field which you can use to page between.
SELECT *
FROM
( SELECT Row_Number() OVER(ORDER BY UserName) As RowID, UserFirstName, UserLastName
FROM Users
) As RowResults
WHERE RowID Between 5 AND 10
etc
If you're trying to get it in one statement (the total plus the paging). You might need to explore SQL Server support for the partition by clause (windowing functions in ANSI SQL terms). In Oracle the syntax is just like the example above using row_number(), but I have also added a partition by clause to get the total number of rows included with each row returned in the paging (total rows is 1,262):
SELECT rn, total_rows, x.OWNER, x.object_name, x.object_type
FROM (SELECT COUNT (*) OVER (PARTITION BY owner) AS TOTAL_ROWS,
ROW_NUMBER () OVER (ORDER BY 1) AS rn, uo.*
FROM all_objects uo
WHERE owner = 'CSEIS') x
WHERE rn BETWEEN 6 AND 10
Note that I have where owner = 'CSEIS' and my partition by is on owner. So the results are:
RN TOTAL_ROWS OWNER OBJECT_NAME OBJECT_TYPE
6 1262 CSEIS CG$BDS_MODIFICATION_TYPES TRIGGER
7 1262 CSEIS CG$AUS_MODIFICATION_TYPES TRIGGER
8 1262 CSEIS CG$BDR_MODIFICATION_TYPES TRIGGER
9 1262 CSEIS CG$ADS_MODIFICATION_TYPES TRIGGER
10 1262 CSEIS CG$BIS_LANGUAGES TRIGGER
The accepted answer for this doesn't actually work for me...I had to jump through one more hoop to get it to work.
When I tried the answer
SELECT Row_Number() OVER(ORDER BY UserName) As RowID, UserFirstName, UserLastName
FROM Users
WHERE RowID Between 0 AND 9
it failed, complaining that it didn't know what RowID was.
I had to wrap it in an inner select like this:
SELECT *
FROM
(SELECT
Row_Number() OVER(ORDER BY UserName) As RowID, UserFirstName, UserLastName
FROM Users
) innerSelect
WHERE RowID Between 0 AND 9
and then it worked.
When I need to do paging, I typically use a temporary table as well. You can use an output parameter to return the total number of records. The case statements in the select allow you to sort the data on specific columns without needing to resort to dynamic SQL.
--Declaration--
--Variables
#StartIndex INT,
#PageSize INT,
#SortColumn VARCHAR(50),
#SortDirection CHAR(3),
#Results INT OUTPUT
--Statements--
SELECT #Results = COUNT(ID) FROM Customers
WHERE FirstName LIKE '%a%'
SET #StartIndex = #StartIndex - 1 --Either do this here or in code, but be consistent
CREATE TABLE #Page(ROW INT IDENTITY(1,1) NOT NULL, id INT, sorting_1 SQL_VARIANT, sorting_2 SQL_VARIANT)
INSERT INTO #Page(ID, sorting_1, sorting_2)
SELECT TOP (#StartIndex + #PageSize)
ID,
CASE
WHEN #SortColumn='FirstName' AND #SortDirection='ASC' THEN CAST(FirstName AS SQL_VARIANT)
WHEN #SortColumn='LastName' AND #SortDirection='ASC' THEN CAST(LastName AS SQL_VARIANT)
ELSE NULL
END AS sort_1,
CASE
WHEN #SortColumn='FirstName' AND #SortDirection='DES' THEN CAST(FirstName AS SQL_VARIANT)
WHEN #SortColumn='LastName' AND #SortDirection='DES' THEN CAST(LastName AS SQL_VARIANT)
ELSE NULL
END AS sort_2
FROM (
SELECT
CustomerId AS ID,
FirstName,
LastName
FROM Customers
WHERE
FirstName LIKE '%a%'
) C
ORDER BY sort_1 ASC, sort_2 DESC, ID ASC;
SELECT
ID,
Customers.FirstName,
Customers.LastName
FROM #Page
INNER JOIN Customers ON
ID = Customers.CustomerId
WHERE ROW > #StartIndex AND ROW <= (#StartIndex + #PageSize)
ORDER BY ROW ASC
DROP TABLE #Page
I believe you'd need to perform a separate query to accomplish that unfortionately.
I was able to accomplish this at my previous position using some help from this page:
Paging in DotNet 2.0
They also have it pulling a row count seperately.
Here's what I do for paging: All of my big queries that need to be paged are coded as inserts into a temp table. The temp table has an identity field that will act in a similar manner to the row_number() mentioned above. I store the number of rows in the temp table in an output parameter so the calling code knows how many total records there are. The calling code also specifies which page it wants, and how many rows per page, which are selected out from the temp table.
The cool thing about doing it this way is that I also have an "Export" link that allows you to get all rows from the report returned as CSV above every grid in my application. This link uses the same stored procedure: you just return the contents of the temp table instead of doing the paging logic. This placates users who hate paging, and want to see everything, and want to sort it in a million different ways.