SQL: Multiple SELECTs instead of JOIN - sql-server

I am not completely new to SQL, but this time I am slow on the uptake.
For a data export, I have to select some user data including two JOINs. The data is not related, I just need both information in one export sheet.
I have created a example. The column groupname is from one JOIN and the column course from the other JOIN:
╔════╦═══════════╦══════════╦═══════════╦════════════╗
║ id ║ firstname ║ lastname ║ groupname ║ course ║
╠════╬═══════════╬══════════╬═══════════╬════════════╣
║ 1 ║ John ║ Doe ║ Manager ║ Management ║
║ 1 ║ John ║ Doe ║ CEO ║ Management ║
║ 1 ║ John ║ Doe ║ Manager ║ Logistics ║
║ 1 ║ John ║ Doe ║ CEO ║ Logistics ║
║ 1 ║ John ║ Doe ║ Manager ║ Leadership ║
║ 1 ║ John ║ Doe ║ CEO ║ Leadership ║
╚════╩═══════════╩══════════╩═══════════╩════════════╝
Due to the nature of JOINS; the groupname-column is duplicated now several times. But what I actually want, is something like this:
╔════╦═══════════╦══════════╦═══════════╦════════════╗
║ id ║ firstname ║ lastname ║ groupname ║ course ║
╠════╬═══════════╬══════════╬═══════════╬════════════╣
║ 1 ║ John ║ Doe ║ Manager ║ ║
║ 1 ║ John ║ Doe ║ CEO ║ ║
║ 1 ║ John ║ Doe ║ ║ Management ║
║ 1 ║ John ║ Doe ║ ║ Logistics ║
║ 1 ║ John ║ Doe ║ ║ Leadership ║
╚════╩═══════════╩══════════╩═══════════╩════════════╝
I guess, doing two SELECT-Statements consecutively would be the better option. Unfortunately, the original query with JOINS and where-Arguments has like 25 lines of code, so I would not like to duplicate it.
Is there a way to achieve my way of output more easily then doing for example a UNION with two long queries (see below for simple example in this case)?
SELECT u.[id]
,[firstname]
,[lastname]
,groupname
,'' AS course
FROM [dbo].[users] u
JOIN dbo.groups g ON u.id = g.userId
UNION ALL
SELECT u.[id]
,[firstname]
,[lastname]
,'' AS groupname
,course
FROM [dbo].[users] u
JOIN dbo.courses c ON u.id = c.userId

You could create a Table-Valued UDF with the query in question and then make a UNION ALL with the two UDFs
Pro:
- Much shorter Query:
SELECT * FROM [MY_UDF](Param 1, Param 2, ...)<br/>
UNION ALL<br/>
SELECT * FROM [MY_UDF](Different Param 1, Different Param 2, ...)
Con:
- You have to create the table valued UDF.
Otherwise: I think QUERY_1 UNION ALL QUERY_2 is probably the way to go.

I think their is a lot of way to solve your problem. I will give you the best way I can think of.
First Solution : Simply use a WITH not to repeat your common part query as follow:
WITH CommonPart (id, firstname, lastname)
AS
(
Select id, firstname, lastname
From [dbo].[users]
-- Eventually a filter ...
)
SELECT cp.*
, g.groupname
, '' AS course
FROM CommonPart cp
JOIN dbo.groups g ON cp.id = g.userId
UNION ALL
SELECT cp.*
,'' AS groupname
,c.course
FROM CommonPart cp
JOIN dbo.courses c ON cp.id = c.userId
Second Solution : You can Insert null values into courses and groups and use a simple LEFT JOIN. But I don't like this second solution.
EDIT: After Insert of null values, it would look like:
Select u.id,
u.firstname,
u.lastname,
g.groupname,
c.course
From [dbo].[users] u
Left Join [dbo].[groups] g ON g.userId = u.id
Left Join [dbo].[courses] c ON c.userId = u.id
Where (g.groupname IS NULL and c.course IS NOT NULL)
OR (g.groupname IS NOT NULL and c.course IS NULL)

Related

dynamic sql embedded in select query

I have a table Users,
╔════╦═══════╦══════╗
║ Id ║ Name ║ Db ║
╠════╬═══════╬══════╣
║ 1 ║ Peter ║ DB1 ║
║ 2 ║ John ║ DB16 ║
║ 3 ║ Alex ║ DB23 ║
╚════╩═══════╩══════╝
and many databases that have the same structure (Same tables, same procedures, ...), so every database have a table named Project, and this is the structure of Project table,
╔════╦═════════╦═════════════╗
║ Id ║ Request ║ Information ║
╠════╬═════════╬═════════════╣
║ 1 ║ 126 ║ XB1 ║
║ 2 ║ 126 ║ D6 ║
║ 3 ║ 202 ║ BM-23 ║
╚════╩═════════╩═════════════╝
So, when I query a database :
SELECT count(distinct([Request])) as nbrRequests
FROM [SRV02].[DB1].[dbo].[Project]
I get this result :
╔═════════════╗
║ NbrRequests ║
╠═════════════╣
║ 2 ║
╚═════════════╝
Now, what I want is to "link"/"join" ... results from the table Users to this query, where the column Db in Users table is the name of my database, so I can get a result like this :
╔════╦═══════╦══════╦═════════════╗
║ Id ║ Name ║ Db ║ NbrRequests ║
╠════╬═══════╬══════╬═════════════╣
║ 1 ║ Peter ║ DB1 ║ 2 ║
║ 2 ║ John ║ DB16 ║ 3 ║
║ 3 ║ Alex ║ DB23 ║ 6 ║
╚════╩═══════╩══════╩═════════════╝
I'm trying with dynamic SQL, but no luck.
NB : Every user has only one database, and a database belong to only one user, it's one-to-one relationship
The way you can do it is with a UNION counting every specific database table and giving it a identification for the database, like this:
SELECT u.Id, u.Name, u.Db, dbCts.nbrRequests
FROM [Users] u INNER JOIN
(SELECT 'DB1' as db, count(distinct([Request])) as nbrRequests
FROM [SRV02].[DB1].[dbo].[Project]
UNION
SELECT 'DB16', count(distinct([Request])) as nbrRequests
FROM [SRV02].[DB16].[dbo].[Project]
UNION
SELECT 'DB23', count(distinct([Request])) as nbrRequests
FROM [SRV02].[DB23].[dbo].[Project]
) dbCts ON u.Db = dbCts.db
Don't forget to add the server and schema to the Users table I didn't because there is no such info on your question.
Also in order to do this, your connected user must have privileges on all databases.
Dynamic SQL can be very tricky.
This example builds the select query from the users table. The variable #Query is incremented for each line returned by the Users table. Each row returns a query that joins the local users table to the projects table in a remote db. The results of each query are UNIONED together.
Example
-- Wil holds our dynamic query.
DECLARE #Query NVARCHAR(MAX) = '';
-- Builds our dynamic statement.
SELECT
#Query =
#Query
+ CASE WHEN LEN(#Query) > 0 THEN ' UNION ALL ' ELSE '' END
+ 'SELECT u.Id, u.Name, u.Db, COUNT(DISTINCT p.Request) AS NbrRequest '
+ 'FROM [SVR02].' + QUOTENAME(DB) + 'dbo.Project AS p INNER JOIN Users u ON u.Db= p.Db '
+ 'GROUP BY u.Id, u.Name, u.Db'
FROM
Users
;
-- Executes the dynamic statement.
EXECUTE (#Query);
This example uses QUOTENAME to help avoid SQL injection attacks.
Combining these 2 answers https://stackoverflow.com/a/35795690/1460399 and https://stackoverflow.com/a/35795189/1460399, I got this solution :
DECLARE #Query NVARCHAR(MAX)= 'SELECT u.Id, u.Name, u.Db, dbCts.nbrRequests FROM [Users] u INNER JOIN (';
DECLARE #QueryLength INT= LEN(#Query);
SELECT #Query = #Query
+CASE WHEN LEN(#Query) > #QueryLength THEN ' UNION ' ELSE '' END
+'SELECT '''+Db+''' as db, count(distinct(Request)) as nbrRequests FROM [SRV02].'+Db+'[Project]'
FROM Users;
SET #Query = #Query+') dbCts ON u.Db = dbCts.db';
EXECUTE (#Query);

Full text search returning only one row and not a set

I have a full text search catalog and index set up on my table.
I first tried to run the query below with only one row in the table and it worked by returning the row I was looking based on the string 'test'. But when I placed a second row into the table it still only returned one row, not two rows. I'm trying to get it to return more then one row and I'm not sure why it's not. Any help would be appreciated.
Query's attempted
SELECT *
FROM dbo.Gifts
WHERE CONTAINS(Name, 'test')
SELECT *
FROM dbo.Gifts
WHERE CONTAINS(Name, '"test gift"')
SELECT *
FROM dbo.Gifts
WHERE FREETEXT (Name, 'test gift')
SELECT *
FROM dbo.Gifts
WHERE FREETEXT(Name, 'test')
and here are the two rows in the table
╔════════╦════════════╦════════╦════════╦═════════╦══════════════╦═══════════╗
║ GiftId ║ Name ║ Rating ║ Status ║ OwnerId ║ Availability ║ Thumbnail ║
╠════════╬════════════╬════════╬════════╬═════════╬══════════════╬═══════════╣
║ 1 ║ test gift ║ 5 ║ 0 ║ 1 ║ 0 ║ NULL ║
║ 2 ║ test gift1 ║ 2 ║ 0 ║ 1 ║ 0 ║ NULL ║
╚════════╩════════════╩════════╩════════╩═════════╩══════════════╩═══════════╝
Only the first row is being returned with giftid = 1 and I want both rows to be returned.

Update column in related table with data from a join

I have three tables that hold data on physicians and the practices and health care organizations they belong to. For example ..
[Table Hmo]
╔════╦════════════════════════════════════╗
║ Id ║ Name ║
╠════╬════════════════════════════════════╣
║ 1 ║ Purple Cross and Yellow Shield HMO ║
║ 2 ║ Tifts Health HMO ║
╚════╩════════════════════════════════════╝
[Table Practices]
╔════╦═══════╦═════════════════════════╗
║ Id ║ HmoId ║ Name ║
╠════╬═══════╬═════════════════════════╣
║ 1 ║ 1 ║ Downtown Cardiac Group ║
║ 2 ║ 1 ║ Tropical Medicine Group ║
║ 3 ║ 2 ║ Action SportsMed Group ║
╚════╩═══════╩═════════════════════════╝
[Table Physicians]
╔════╦═══════╦════════════╦══════════════════╗
║ Id ║ HmoId ║ PracticeId ║ Name ║
╠════╬═══════╬════════════╬══════════════════╣
║ 1 ║ ? ║ 1 ║ Dr. Trapper-John ║
║ 2 ║ ? ║ 1 ║ Dr. Doolittle ║
║ 3 ║ ? ║ 2 ║ Dr. Smith ║
║ 4 ║ ? ║ 3 ║ Dr. Flintstone ║
╚════╩═══════╩════════════╩══════════════════╝
I know the HmoId column is not necessary because the tables are linked by foreign keys, however, the user would neverthless still like to have this column populated. What I can't figure out is how to populate the HmoId column using an update query.
I can write a query to obtain the HmoId for each physician ...
SELECT Physicians.Name, Hmo.Name
FROM Physicians
LEFT JOIN Practices ON Physicians.PracticeId = Practices.Id
LEFT JOIN Hmo ON Practices.HmoId = Hmo.Id
But how to translate that to an update query eludes me.
Update p set
p.hmoid = h.id
FROM Physicians p
LEFT JOIN Practices pr ON pr.id = p.practiceid
LEFT JOIN Hmo h ON h.id = pr.HmoId

MSSQL - Retrieve ID if condition for all rows of this ID is valid

Just a quick question. I have table like this:
╔══════╦═════════════╗
║ id ║ date ║
╠══════╬═════════════╣
║ 90 ║ 2100-01-01 ║
║ 90 ║ 2100-01-01 ║
║ 91 ║ 2100-01-01 ║
║ 91 ║ null ║
║ 92 ║ 2100-01-01 ║
║ 92 ║ 2100-01-01 ║
║ 92 ║ null ║
║ 93 ║ 2100-01-01 ║
╚══════╩═════════════╝
I want to write a query that will retrieve only those IDs that have a date higher than current date in ALL of its rows. I that case:
╔════╗
║ id ║
╠════╣
║ 90 ║
║ 93 ║
╚════╝
Thanks!
Try this:
SELECT distinct id
FROM table1
WHERE id NOT IN (SELECT id
FROM table1
WHERE isnull(date,'') < Getdate())
Take a look at a working example on SQL Fiddle
So you want to find all ID's where all dates are in the future? I would use NOT EXISTS:
SELECT distinct(id)
FROM table1 t1
WHERE NOT EXISTS
(
SELECT 1 FROM table1 t2
WHERE t2.id = t1.id
AND ISNULL(t2.date, GETDATE()) <= GetDate()
)
Demo
The idea is, to create a subquery which returns those same ids, where the minimum date (within the same ids) is bigger than the current date. I like to use the outer SQL too, because as soon as you want to add columns to the output, you have to create it anyway if you do not want to retouch the group by.
SELECT id
FROM tab
WHERE id in
(SELECT id
FROM tab
GROUP BY id
HAVING MIN(IFNULL(date, GETDATE())) > GETDATE())
GROUP BY id

Sql Server Get Instance Id of New Job

This question is similar, but not quite what I'm looking for: Executing SQL Server Agent Job from a stored procedure and returning job result
I'd like to run a job and return the instance ID for recording in a separate table for reporting. We get daily extracts of files and when we've pre-processed the files we kick off a SQL Agent Job. The same job might get kicked off multiple times in short order, so we need the instance id immediately.
Furthermore, I'm showing the results on a small dash that could really use a "Job Completion Time" column. Right now I've got a separate page that only shows the most recent job status. There's no way to connect the job w/ the completion date.
I suppose that running the job and immediately querying for the highest instance ID of that job would do the trick, but I was really hoping for something a bit more foolproof.
To get the details of Jobs executed you can use the following query aginst dbo.sysjobs and dbo.sysjobhistory tables in MSDB database.
select
j.name as 'JobName',
h.instance_id,
run_date,
run_time,
msdb.dbo.agent_datetime(run_date, run_time) as 'RunDateTime',
run_duration
From msdb.dbo.sysjobs j
INNER JOIN msdb.dbo.sysjobhistory h
ON j.job_id = h.job_id
where j.enabled = 1 --Only Enabled Jobs
order by run_date, RunDateTime desc
Result Set
╔═══════════════════════════════════════════════════╦═════════════╦══════════╦══════════╦═════════════════════════╦══════════════╗
║ JobName ║ instance_id ║ run_date ║ run_time ║ RunDateTime ║ run_duration ║
╠═══════════════════════════════════════════════════╬═════════════╬══════════╬══════════╬═════════════════════════╬══════════════╣
║ sysDatabase_weekly_Full_Backup_MyServer.Subplan_1 ║ 1769 ║ 20130910 ║ 110052 ║ 2013-09-10 11:00:52.000 ║ 3 ║
║ sysDatabase_weekly_Full_Backup_MyServer.Subplan_1 ║ 1770 ║ 20130910 ║ 110052 ║ 2013-09-10 11:00:52.000 ║ 3 ║
║ sysDatabase_weekly_Full_Backup_MyServer.Subplan_1 ║ 2025 ║ 20130915 ║ 20001 ║ 2013-09-15 02:00:01.000 ║ 4 ║
║ sysDatabase_weekly_Full_Backup_MyServer.Subplan_1 ║ 2026 ║ 20130915 ║ 20000 ║ 2013-09-15 02:00:00.000 ║ 5 ║
║ sysDatabase_weekly_Full_Backup_MyServer.Subplan_1 ║ 2415 ║ 20130922 ║ 20000 ║ 2013-09-22 02:00:00.000 ║ 17 ║
║ sysDatabase_weekly_Full_Backup_MyServer.Subplan_1 ║ 2416 ║ 20130922 ║ 20000 ║ 2013-09-22 02:00:00.000 ║ 17 ║
║ sysDatabase_weekly_Full_Backup_MyServer.Subplan_1 ║ 8804 ║ 20130929 ║ 20000 ║ 2013-09-29 02:00:00.000 ║ 4 ║
╚═══════════════════════════════════════════════════╩═════════════╩══════════╩══════════╩═════════════════════════╩══════════════╝
To see some more cool queries about how to query sql server agent's Job history read this Querying SQL Server Agent Job History Data by Chad Churchwell

Resources