Update column in related table with data from a join - sql-server

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

Related

SQL: Multiple SELECTs instead of JOIN

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)

Filtering by many-to-many table

I'm havin hard time to understand how to filter out result of multidimensional expression.
This is my database schema.
And this is my data.
Manufacturer
╔════╦═══════════════════╗
║ Id ║ Name ║
╠════╬═══════════════════╣
║ 1 ║ Awesome Computers ║
║ 2 ║ TailSpin Toys ║
╚════╩═══════════════════╝
Item
╔════╦═════════╦════════════════╦═══════╗
║ Id ║ Name ║ ManufacturerId ║ Stock ║
╠════╬═════════╬════════════════╬═══════╣
║ 1 ║ PC ║ 1 ║ 40 ║
║ 2 ║ Server ║ 1 ║ 10 ║
║ 3 ║ STB ║ 2 ║ 80 ║
║ 4 ║ Console ║ 2 ║ 50 ║
╚════╩═════════╩════════════════╩═══════╝
Part
╔════╦══════════════════╦════════╦══════════╦═══════╗
║ Id ║ Name ║ ItemId ║ StatusId ║ Stock ║
╠════╬══════════════════╬════════╬══════════╬═══════╣
║ 1 ║ MBO ║ 1 ║ 1 ║ 100 ║
║ 2 ║ Processor ║ 1 ║ 1 ║ 100 ║
║ 3 ║ Server MBO ║ 2 ║ 2 ║ 20 ║
║ 4 ║ Server processor ║ 2 ║ 2 ║ 20 ║
║ 5 ║ Main box ║ 3 ║ 2 ║ 40 ║
║ 7 ║ Adapter ║ 3 ║ 3 ║ 30 ║
║ 8 ║ Controller ║ 4 ║ 2 ║ 40 ║
║ 10 ║ Adapter ║ 4 ║ 1 ║ 60 ║
║ 11 ║ Memory card ║ 4 ║ 2 ║ 80 ║
╚════╩══════════════════╩════════╩══════════╩═══════╝
Status
╔════╦═════════════╗
║ Id ║ Name ║
╠════╬═════════════╣
║ 1 ║ No data ║
║ 2 ║ Available ║
║ 3 ║ Unavailable ║
╚════╩═════════════╝
I imported everything into the tabular model solution.
After this, I created two measures:
Table Item: ItemStock:=SUM([Stock])
Table Part: PartStock:=SUM([Stock])
Then I deployed the cube to the server.
By running the following MDX query...
SELECT
NON EMPTY {
[Part].[Name].CHILDREN
} ON ROWS,
{
[Measures].[PartStock]
} ON COLUMNS
FROM [Model]
WHERE (
{
[Status].[Id].&[1]
}
)
...I get this resultset...
╔═══════════╦═══════════╗
║ ║ PartStock ║
╠═══════════╬═══════════╣
║ Adapter ║ 60 ║
║ MBO ║ 100 ║
║ Processor ║ 100 ║
╚═══════════╩═══════════╝
...which is ok.
However, when running this MDX query...
SELECT
NON EMPTY {
[Item].[Name].CHILDREN
} ON ROWS,
{
[Measures].[ItemStock]
} ON COLUMNS
FROM [Model]
WHERE (
{
[Status].[Id].&[1]
}
)
...I'm getting this resultset...
╔═════════╦═══════════╗
║ ║ ItemStock ║
╠═════════╬═══════════╣
║ Console ║ 50 ║
║ PC ║ 40 ║
║ Server ║ 10 ║
║ STB ║ 80 ║
╚═════════╩═══════════╝
I was expecting that items in the ItemStock table would be filtered out by Part table as a many-to-many relationship. E.g. MBO, Processor and Adapter have references to items 1 and 4, so the result would be constrained to them, and the result should turn out like this:
╔═════════╦═══════════╗
║ ║ ItemStock ║
╠═════════╬═══════════╣
║ Console ║ 50 ║
║ PC ║ 40 ║
╚═════════╩═══════════╝
What am I doing wrong?
MDX is unknown for me but here is a pure SQL explanation.
Your model is actually like this:
Link to image
To get [Items] for [Parts] with spesific [Status] I would to use this pure SQL:
SELECT Item.Name
FROM Item INNER JOIN Part ON Item.Id = Part.ItemID
WHERE Part.StatusID = 1;
I can see in your sample that you use FROM [Model], but you have no table named Model in your setup - so this might be a VIEW or some functionality for MDX you should look into. It could be that the JOIN between tables are wrong for the [Model] view.

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.

Performance of concatenated column - does order matter?

I need to create a concatenated column based on two other columns in the table. One column is the year (10 distinct values), and one is a person's ID value (~150,000 distinct values). This is being used as a business key by an ETL task that will not accept multiple columns as the key value, so I need to persist this value in my database.
That said, I can choose how to create that value, and I'm wondering if the order (ID + Year or Year + ID) affects performance in any way. If the year goes first, the first four characters will always be one of a limited set of actual years. If the ID goes first, that will change for each user. Is there any difference between the two?
The only usage this column will get is during the ETL load, where it will be used to join data from the source and staging tables to check for differences between the two. The base values will be in the table underneath, and I plan on creating a clustered index on those base values.
Sample Data:
╔══════════════╦══════════════╦═════════╦═════════╗
║ COMPOSITE_1 ║ COMPOSITE_2 ║ AC_YEAR ║ ST_ID ║
╠══════════════╬══════════════╬═════════╬═════════╣
║ 0000001|2005 ║ 2005|0000001 ║ 2005 ║ 0000001 ║
║ 0000001|2006 ║ 2006|0000001 ║ 2006 ║ 0000001 ║
║ 0000001|2009 ║ 2009|0000001 ║ 2009 ║ 0000001 ║
║ 0000001|2010 ║ 2010|0000001 ║ 2010 ║ 0000001 ║
║ 0000001|2012 ║ 2012|0000001 ║ 2012 ║ 0000001 ║
║ 0000001|2013 ║ 2013|0000001 ║ 2013 ║ 0000001 ║
║ 0000002|2005 ║ 2005|0000002 ║ 2005 ║ 0000002 ║
║ 0000002|2006 ║ 2006|0000002 ║ 2006 ║ 0000002 ║
║ 0000002|2007 ║ 2007|0000002 ║ 2007 ║ 0000002 ║
║ 0000002|2008 ║ 2008|0000002 ║ 2008 ║ 0000002 ║
║ 0000002|2009 ║ 2009|0000002 ║ 2009 ║ 0000002 ║
║ 0000002|2010 ║ 2010|0000002 ║ 2010 ║ 0000002 ║
║ 0000002|2012 ║ 2012|0000002 ║ 2012 ║ 0000002 ║
║ 0000002|2013 ║ 2013|0000002 ║ 2013 ║ 0000002 ║
║ 0000002|2014 ║ 2014|0000002 ║ 2014 ║ 0000002 ║
╚══════════════╩══════════════╩═════════╩═════════╝
Question One: would either Composite_1 or Composite_2 give me better performance during the JOIN?
Question Two: would I ever need to index the Composite column, and if so should I do it alone/with others? The SSIS task will be using it for an in-memory JOIN, and I plan to include it as an ORDER BY within my OLE DB Source component.
Question Three: Does the clustered index belong on the Composite column, or the Year and ID columns? EDIT: Or, since I know that Year and ID won't affect the order of Composite, should I just include all three?
Since you're turning these into a string column, the index is going to order them based on the characters in the string. You'll want the field (year or id) with the best distribution and most unique values to be first.
You should index the composite column since it's being used for the join. Whether you want to include other data depends on what data you are pulling back.
If you don't need the clustered index on any other columns, and the table is only being used for BI/data warehouse loading, you may as well put it on the composite column. That way a key lookup won't be required to get any other data you may need.

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