MS SQL variable add value from count in the same statement - sql-server

I have this Select statement
select Id, UserName, from UserTable where Department= #DepartmentInput
and a variable to calculate how many users from the department
#UserCounter
Is there a way to add count(the number of users from the department) into #UserCounter from the select statement should the statement runs in a while loop?

Presuming sql-server:
select Id, UserName, #UserCounter = Count(*) OVER (Partition By Department)
from UserTable
where Department= #DepartmentInput
Otherwise a simple sub-query should work too:
select Id, UserName, #UserCounter = (select count(*) from UserTable
where Department= #DepartmentInput)
from UserTable
where Department= #DepartmentInput
The database should be clever enough to optimize that query so that the subquery doesn't need to be avaulated for every (matching) row.

Related

Sql Select query on select query result

I am trying to (select)query inside the previous (select)query from same table.
I've tried this below;
CREATE PROCEDURE dbo.strprcReturnEmpDetails(#EmpID VARCHAR(25))
AS
SELECT [Name],
Role,
Email,
Department,
ReportingAuthority,
DomainID,
ReportsTo,
(
SELECT DISTINCT
EmpID
FROM Login
WHERE [Name] = ReportsTo
) AS approverEmpid
FROM Login
WHERE EmpID = 288;
SET NOCOUNT ON;
RETURN;
I believe you just miss the aliases in the subquery to make it work. Your subquery returns more than one value, you need to make it a dependent subquery as follows:
SELECT [Name], Role, Email, Department, ReportingAuthority,DomainID,ReportsTo,
(
select distinct EmpID
from Login l2
where l2.Name = l1.ReportsTo
) as approverEmpid
FROM Login l1
WHERE EmpID=288
This should work if Name in Login table is unique.

SQL SELECT from SELECT

I am trying to build a single select statement from two separate ones.
Basically I have a list of Names in a table which do repeat like so:
Name| Date
John 2014-11-22
John 2013-02-03
Joe 2012-12-12
Jack 2011-11-11
Bob 2010-10-01
Bob 2013-12-22
I need to do a Select distinct Name from Records which returns John, Joe, Jack, Bob.
I then want to so a Select on another table where I pass in the rows returned above.
SELECT Address, Phone From dbo.Details
WHERE Name = {Values from first SELECT query}
Having trouble with the syntax.
If you do not want to return any values from the subquery, you can use either IN or EXISTS
SELECT Address, Phone From dbo.Details
WHERE Name IN (SELECT DISTINCT Name FROM Records)
-- OR --
SELECT Address, Phone From dbo.Details D
WHERE EXISTS (SELECT 1 FROM Records R WHERE R.Name = D.Name)
(In most RDBMS the EXISTS is less resource intensive).
If you want to return values from the subquery, you should use JOIN
SELECT
D.Address,
D.Phone,
R.Name -- For example
FROM
dbo.Details D
INNER JOIN dbo.Records R
ON D.Name = R.Name
SIDENOTE These are sample queries, it is possible that you have to fine tune them to match your exact requirements.
You can use:
SELECT Address, Phone, name
FROM details
-- "in" is the difference from your first query, needed due to multiple values being returned by the subquery
WHERE name in (
SELECT distinct name
FROM namesTable
)
Additionally the following should work:
SELECT d.Address, d.Phone, n.name
FROM details d
inner join (
select distinct name
from namesTable
) n on d.name = n.name
So there are two ways you can go about doing this. One, create a temporary table and perform a join (*actually in retrospect you could also join to your second table as a subquery, or use something like a CTE if you're using SQL SERVER, but the modifications if you wanted to go that route should be pretty obvious)
CREATE TEMPORARY TABLE my_table AS
{your first select query};
SELECT Address, Phone From dbo.Details
INNER JOIN my_table AS mt
ON mt.name = dbo.name
Another option would be to perform an IN or EXISTS query using your select query
SELECT Address, Phone From dbo.Details
WHERE name IN (SELECT name from my_table)
Or, better yet (eg SQL Server IN vs. EXISTS Performance),
SELECT Address, Phone From dbo.Details
WHERE EXISTS (SELECT * from my_table WHERE my_table.name = dbo.name)
You might have to modify the syntax slightly, depending on if you are using MySQL or SQL Server (not sure about that later, honestly). But this should get you started down the right path
This will give you the names and their address and phone number:
SELECT DISTINCT N.Name, D.Address, D.Phone
FROM dbo.Details D INNER JOIN dbo.Names N ON D.Name = N.Name
When using a subquery that is not scalar (doesn't return only one value) in the where clause use IN and of course only one column in the subquery:
SELECT Address, Phone
From dbo.Details
WHERE Name IN (Select Name from Table)

SELECT INTO query

I have to write an SELECT INTO T-SQL script for a table which has columns acc_number, history_number and note.
How do i facilitate an incremental value of history_number for each record being inserted via SELECT INTO.
Note, that the value for history_number comes off as a different value for each account from a different table.
SELECT history_number = IDENTITY(INT,1,1),
... etc...
INTO NewTable
FROM ExistingTable
WHERE ...
You could use ROW_NUMBER instead of identity i.e. ROW_NUMBER() OVER (ORDER BY )
SELECT acc_number
,o.historynumber
,note
,o.historynumber+DENSE_RANK() OVER (Partition By acc_number ORDER BY Note) AS NewHistoryNumber
--Or some other order by probably a timestamp...
FROM Table t
INNER JOIN OtherTable o
ON ....
Working Fiddle
The will give you an incremented count starting from history number for each accnum. I suggest you use a better order by in the rank but there was not enough info in the question.
This answer to this question may help you as well
Question
Suppose your SELECT statement is like this
SELECT acc_number,
history_number,
note
FROM [Table]
Try this Query as below.
SELECT ROW_NUMBER() OVER (ORDER BY acc_number) ID,
acc_number,
history_number,
note
INTO [NewTable]
FROM [Table]

Multiple Select against one CTE

I have a CTE query filtering a table Student
Student
(
StudentId PK,
FirstName ,
LastName,
GenderId,
ExperienceId,
NationalityId,
CityId
)
Based on a lot filters (multiple cities, gender, multiple experiences (1, 2, 3), multiple nationalites), I create a CTE by using dynamic sql and joining the student table with a user defined tables (CityTable, NationalityTable,...)
After that I have to retrieve the count of student by each filter like
CityId City Count
NationalityId Nationality Count
Same thing the other filter.
Can I do something like
;With CTE(
Select
FROM Student
Inner JOIN ...
INNER JOIN ....)
SELECT CityId,City,Count(studentId)
FROm CTE
GROUP BY CityId,City
SELECT GenderId,Gender,Count
FROM CTE
GROUP BY GenderId,Gender
I want to something like what LinkedIn is doing with search(people search,job search)
http://www.linkedin.com/search/fpsearch?type=people&keywords=sales+manager&pplSearchOrigin=GLHD&pageKey=member-home
It's so fast and do the same thing.
You can not use multiple select but you can use more than one CTE like this.
WITH CTEA
AS
(
SELECT 'Coulmn1' A,'Coulmn2' B
),
CETB
AS
(
SELECT 'CoulmnX' X,'CoulmnY' Y
)
SELECT * FROM CTEA, CETB
For getting count use RowNumber and CTE some think like this.
ROW_NUMBER() OVER ( ORDER BY COLUMN NAME )AS RowNumber,
Count(1) OVER() AS TotalRecordsFound
Please let me know if you need more information on this.
Sample for your reference.
With CTE AS (
Select StudentId, S.CityId, S.GenderId
FROM Student S
Inner JOIN CITY C
ON S.CityId = C.CityId
INNER JOIN GENDER G
ON S.GenderId = G.GenderId)
,
GENDER
AS
(
SELECT GenderId
FROM CTE
GROUP BY GenderId
)
SELECT * FROM GENDER, CTE
It is not possible to get multiple result sets from a single CTE.
You can however use a table variable to cache some of the information and use it later instead of issuing the same complex query multiple times:
declare #relevantStudent table (StudentID int);
insert into #relevantStudent
select s.StudentID from Students s
join ...
where ...
-- now issue the multiple queries
select s.GenderID, count(*)
from student s
join #relevantStudent r on r.StudentID = s.StudentID
group by s.GenderID
select s.CityID, count(*)
from student s
join #relevantStudent r on r.StudentID = s.StudentID
group by s.CityID
The trick is to store only the minimum required information in the table variable.
As with any query whether this will actually improve performance vs. issuing the queries independently depends on many things (how big the table variable data set is, how complex is the query used to populate it and how complex are the subsequent joins/subselects against the table variable, etc.).
Do a UNION ALL to do multiple SELECT and concatenate the results together into one table.
;WITH CTE AS(
SELECT
FROM Student
INNER JOIN ...
INNER JOIN ....)
SELECT CityId,City,Count(studentId),NULL,NULL
FROM CTE
GROUP BY CityId,City
UNION ALL
SELECT NULL,NULL,NULL,GenderId,Gender,Count
FROM CTE
GROUP BY GenderId,Gender
Note: The NULL values above just allow the two results to have matching columns, so the results can be concatenated.
I know this is a very old question, but here's a solution I just used. I have a stored procedure that returns a PAGE of search results, and I also need it to return the total count matching the query parameters.
WITH results AS (...complicated foo here...)
SELECT results.*,
CASE
WHEN #page=0 THEN (SELECT COUNT(*) FROM results)
ELSE -1
END AS totalCount
FROM results
ORDER BY bar
OFFSET #page * #pageSize ROWS FETCH NEXT #pageSize ROWS ONLY;
With this approach, there's a small "hit" on the first results page to get the count, and for the remaining pages, I pass back "-1" to avoid the hit (I assume the number of results won't change during the user session). Even though totalCount is returned for every row of the first page of results, it's only computed once.
My CTE is doing a bunch of filtering based on stored procedure arguments, so I couldn't just move it to a view and query it twice. This approach allows avoid having to duplicate the CTE's logic just to get a count.

Select a random database row based on another query

For internal control we would like to select a single random invoice for each of multiple invoice types and regions.
Here's the SQL to get a set of distinct Invoice Types and Regions
select InvoiceType,RegionID
from Invoices
group by InvoiceType, RegionID
For each row this returns I need to fetch a random row with that InvoiceType and RegionID. This is how I'm fetching random rows:
SELECT top 1
CustomerID
,InvoiceNum
,Name
FROM Invoices
JOIN Customers on Customers.CustomerID=Invoices.CustomerID
where InvoiceType=X and RegionID=Y
ORDER BY NEWID
But I don't know how to run this select statement foreach() row the first statement returns. I could do it programmatically but I would prefer an option using only a stored procedure as this query isn't supposed to need a program.
WITH cteInvoices AS (
SELECT CustomerID, InvoiceNum, Name,
ROW_NUMBER() OVER(PARTITION BY InvoiceType, RegionID ORDER BY NEWID()) AS RowNum
FROM Invoices
)
SELECT c.CustomerID, c.InvoiceNum, c.Name
FROM cteInvoices c
WHERE c.RowNum = 1;

Resources