Multi database search and update - sql-server

I don't know where I made a mistake. My goal is to get 1 database of data and transfer it to another database. In doing this, I must use table 2.
Query:
UPDATE [VSRO_SHARD].[dbo].[_RefObjChar]
SET ID = (SELECT ID
FROM [SRO_VT_SHARD].[dbo].[_RefObjChar]
INNER JOIN
(SELECT Link
FROM [SRO_VT_SHARD].[dbo].[_RefObjCommon]
WHERE CodeName128 LIKE 'MOB_RM%')
)
Update
U
Set
U.ID = O.ID
From MyDatabase.dbo.MyTable AS U
INNER JOIN MyDatabase2.dbo.MyTable2 AS O ON U.ID = O.ID
INNER JOIN MyDatabase2.dbo.MyTable3 AS K ON U.ID = K.Link
Where
K.CodeName128 like '%%'
Problem solved.
INNER JOIN requires AS and ON. Thx #Barmar

Related

SQL Server left join if condition met

I have a problem with my query. I have to do left outer join only if condition is true. If condition is false do another left outer join.
I tried with this but not successfully:
select
*
from
works with(nolock)
if work.type = 1
begin
left outer join
users with(nolock) on users.id = work.owner
else
left outer join
groups with(nolock) on groups.id = work.owner
end
How can I solve this problem?
you should try left join both of them, but inside of the select, take what you want depending on the use case.
SELECT
*,
CASE work.type WHEN '1' THEN 'a.owner' ELSE 'b.owner' END AS owner
FROM
blahblah
left join users on blahblah.user_id = users.id as a,
left join groups as blahblah.groups_id = groups.id as b
You can try below query.
First method:
select
works.*, isnull(users.id, groups.id)
from
works with(nolock)
left outer join
users with(nolock) on users.id = works.owner and work.type = 1
left outer join
groups with(nolock) on groups.id = works.owner
Second method:
if exists (select 1 from works with (nolock) where works.type = 1)
select *
from works with(nolock)
left outer join users with(nolock) on users.id = works.owner
else
select *
from works with(nolock)
left outer join groups with(nolock) on groups.id = works.owner
third method: use dynamic SQL to build query at runtime.
Considering that you want to display all columns (*), then you can conditionally join against both tables by checking the work.type as a join condition:
select
*
from
works
left join users on
users.id = work.owner and
work.type = 1
left join groups on
groups.id = work.owner and
(work.type <> 1 OR work.type IS NULL)
A particular row from the works table can only have a particular value for type, so it will join against users or against groups, but never both. The problem with this solution becomes the displayed columns, since we are joining against both tables, now you have to unify groups and users columns.
You can do this with a bunch of ISNULLs:
select
works.*,
Column1 = ISNULL(users.Column1, groups.Column1),
Column2 = ISNULL(users.Column2, groups.Column2)
from
works
left join users on
users.id = work.owner and
work.type = 1
left join groups on
groups.id = work.owner and
(work.type <> 1 OR work.type IS NULL)
If you need to use the same select repeatedly, you can create a table-valued function to wrap this up so you don't have to code it every time. I'll use the table example to show another alternative, using UNION ALL.
CREATE FUNCTION dbo.GetWorkData (#owner INT) -- assuming its a INT
RETURNS TABLE
AS
RETURN
SELECT
-- Your wanted columns here
FROM
works AS W
INNER JOIN users AS U ON W.owner = U.owner
WHERE
W.owner = #owner AND
W.type = 1
UNION ALL
SELECT
-- Your wanted columns here (must be same data type and order of previous SELECT)
FROM
works AS W
INNER JOIN groups AS U ON W.owner = U.owner
WHERE
W.owner = #owner AND
(W.type <> 1 OR W.type IS NULL)
You can use the function with APPLY:
SELECT
D.*
FROM
works AS W
CROSS APPLY dbo.GetWorkData(W.owner) AS D -- User "OUTER APPLY" if you want works that have no users or groups
You can look into Dynamic SQL. The main idea is that the SQL statement is constructed and compiled at runtime.
You can start here:
Link 1 - MSSQL tips.
or here: Link 2 - official microsoft documentation.

Select row with max value in multiple where condition

I edited the following query based on this page:
Selecting a Record With MAX Value
Select query :
select
Users.Id, Users.[Name], Users.Family, Users.BirthDate,
Users.Mobile, Users.[Description], Users.Email,
Users.UserName, Users.fatherName,
Users.archiveNumber, Users.[Address], Users.IsMarried,
Users.Mazhab,
Cities.CityName, Religions.PersianName, Users.Date_insert,
Users.ImageName,
MaghtaeTahsilis.[Name] as MaghtaeTahsilisName,
FieldStudies.[Name] as FieldStudiesName,
Eductionals.Institute, Eductionals.Moaddal,
Eductionals.FromYear, Eductionals.ToYear
from
Users
left outer join
Eductionals on Users.id = Eductionals.UserID
left outer join
MaghtaeTahsilis on Eductionals.MaghtaeID = MaghtaeTahsilis.ID
left outer join
Cities on Users.City_Id = Cities.Id
left outer join
Religions on Users.Relegion_ID = Religions.ID
left outer join
FieldStudies on Eductionals.FieldStudy_ID = FieldStudies.ID
where
Users.UserName = #code_melli
and Eductionals.MaghtaeID = (select MAX(MaghtaeID) from Eductionals
where Eductionals.UserID = Users.Id)
This command works correctly in choosing MAX value, But if the following statement has a NULL value, no row are returned. I want to show NULL value if it is NULL.
Your left outer joins are being turned into inner joins by the where conditions. Your query should look like:
select u.Id, u.[Name], u.Family, u.BirthDate, u.Mobile, u.[Description], u.Email, u.UserName, u.fatherName,
u.archiveNumber, u.[Address], u.IsMarried, u.Mazhab, c.CityName, r.PersianName, u.Date_insert, u.ImageName,
mt.[Name] As MaghtaeTahsilisName, fs.[Name] As FieldStudiesName, e.Institute, e.Moaddal, e.FromYear, e.ToYear
from Users u left outer join
Eductionals e
on u.id = e.UserID and
e.MaghtaeID = (select MAX(e2.MaghtaeID)
from Eductionals e2
where e2.UserID = u.Id
) left outer join
MaghtaeTahsilis mt
on e.MaghtaeID = mt.ID left outer join
Cities c
on u.City_Id = c.Id left outer join
Religions r
on u.Relegion_ID = r.ID left outer join
FieldStudies fs
on e.FieldStudy_ID = fs.ID
where u.UserName = #code_melli ;
Conditions on the first table -- in a chain of left joins should be in the where clause. On subsequent tables in the on clauses.
You'll notice that I also added table aliases so the query is easier to write and to read.
You can also use window functions:
from Users u left outer join
(select e2.*,
row_number() over (partition by e2.userId order by e2.MaghtaeID desc) as seqnum
from Eductionals e2
) e
on u.id = e.UserID and
e.seqnum = 1 left outer join
. . .
Reason for returning zero records when second query returns NULL is, when second query returns NULL, your SQL syntax become like this
And Eductionals.MaghtaeID=NULL
And probably Dbtable Educationals holds NULL values for field MaghtaeID.
So SQL fails above syntax and thus returns zero records.
Correct syntax for checking NULL values would be
And Eductionals.MaghtaeID is NULL
So please modify where condition in your query as follows which will return desired result.
where Users.UserName = #code_melli AND isnull(Eductionals.MaghtaeID,0) = isnull((select MAX(MaghtaeID) from Eductionals where Eductionals.UserID = Users.Id),0)

SQL Query joining parent table with several children rows into one row

I'm trying to implement query to take setups information from database where one setup has link to several items types: Controller, platform and KVM device.
This way:
Rack
|
Setup
/ | \
controller Platform KVM
Connections between parent and children are stored in another table.
I tried the bellow query, but I got setup children in separated rows.
How can I improve query to solve this?
Query:
select R.Id as Rack_Id,
S.Id,C.Id as Setup_Id,
P.Id as Platform_Id,
K.Id as KVM_Id,
R.Capacity, R.[Rack location],
S.[Location in Rack], C.[Controller IP], P.ISMP, P.Platform
From #Racks R join LinksAre LR on LR.SourceId = R.Id
join #Setups S on LR.TargetId=S.Id
left join LinksAre LS on LS.SourceId = S.Id
left join #KVMs K on LS.TargetID = K.Id
left join #Controllers C on LS.TargetId=C.Id
left join #Platforms P on LS.TargetId = P.Id
order by R.Id, S.Id
Thanks!
Think you might need a subquery:
select R.Id as Rack_Id,
S.Id,C.Id as Setup_Id,
P.Id as Platform_Id,
K.Id as KVM_Id,
R.Capacity, R.[Rack location],
( SELECT S.[Location in Rack] FROM #Setups S
WHERE S.ID = LR.TargetId) AS ColumnA,
C.[Controller IP],
P.ISMP, P.Platform
From #Racks R join LinksAre LR on LR.SourceId = R.Id
left join LinksAre LS on LS.SourceId = S.Id
left join #KVMs K on LS.TargetID = K.Id
left join #Controllers C on LS.TargetId=C.Id
left join #Platforms P on LS.TargetId = P.Id
order by R.Id, S.Id

Top 1 with a left join

Given the query below there might be multiple rows in dps_markers with the same marker key but we only want to join against the first. If I take this query and remove the top 1 and ORDER BY I get a value for mbg.marker_value but run as it is it always returns null
SELECT u.id, mbg.marker_value
FROM dps_user u
LEFT JOIN
(SELECT TOP 1 m.marker_value, um.profile_id
FROM dps_usr_markers um (NOLOCK)
INNER JOIN dps_markers m (NOLOCK)
ON m.marker_id= um.marker_id AND
m.marker_key = 'moneyBackGuaranteeLength'
ORDER BY m.creation_date
) MBG ON MBG.profile_id=u.id
WHERE u.id = 'u162231993'
Use OUTER APPLY instead of LEFT JOIN:
SELECT u.id, mbg.marker_value
FROM dps_user u
OUTER APPLY
(SELECT TOP 1 m.marker_value, um.profile_id
FROM dps_usr_markers um (NOLOCK)
INNER JOIN dps_markers m (NOLOCK)
ON m.marker_id= um.marker_id AND
m.marker_key = 'moneyBackGuaranteeLength'
WHERE um.profile_id=u.id
ORDER BY m.creation_date
) AS MBG
WHERE u.id = 'u162231993';
Unlike JOIN, APPLY allows you to reference the u.id inside the inner query.
The key to debugging situations like these is to run the subquery/inline view on its' own to see what the output is:
SELECT TOP 1
dm.marker_value,
dum.profile_id
FROM DPS_USR_MARKERS dum (NOLOCK)
JOIN DPS_MARKERS dm (NOLOCK) ON dm.marker_id= dum.marker_id
AND dm.marker_key = 'moneyBackGuaranteeLength'
ORDER BY dm.creation_date
Running that, you would see that the profile_id value didn't match the u.id value of u162231993, which would explain why any mbg references would return null (thanks to the left join; you wouldn't get anything if it were an inner join).
You've coded yourself into a corner using TOP, because now you have to tweak the query if you want to run it for other users. A better approach would be:
SELECT u.id,
x.marker_value
FROM DPS_USER u
LEFT JOIN (SELECT dum.profile_id,
dm.marker_value,
dm.creation_date
FROM DPS_USR_MARKERS dum (NOLOCK)
JOIN DPS_MARKERS dm (NOLOCK) ON dm.marker_id= dum.marker_id
AND dm.marker_key = 'moneyBackGuaranteeLength'
) x ON x.profile_id = u.id
JOIN (SELECT dum.profile_id,
MAX(dm.creation_date) 'max_create_date'
FROM DPS_USR_MARKERS dum (NOLOCK)
JOIN DPS_MARKERS dm (NOLOCK) ON dm.marker_id= dum.marker_id
AND dm.marker_key = 'moneyBackGuaranteeLength'
GROUP BY dum.profile_id) y ON y.profile_id = x.profile_id
AND y.max_create_date = x.creation_date
WHERE u.id = 'u162231993'
With that, you can change the id value in the where clause to check records for any user in the system.
Because the TOP 1 from the ordered sub-query does not have profile_id = 'u162231993'
Remove where u.id = 'u162231993' and see results then.
Run the sub-query separately to understand what's going on.
Damir is correct,
Your subquery needs to ensure that dps_user.id equals um.profile_id, otherwise it will grab the top row which might, but probably not equal your id of 'u162231993'
Your query should look like this:
SELECT u.id, mbg.marker_value
FROM dps_user u
LEFT JOIN
(SELECT TOP 1 m.marker_value, um.profile_id
FROM dps_usr_markers um (NOLOCK)
INNER JOIN dps_markers m (NOLOCK)
ON m.marker_id= um.marker_id AND
m.marker_key = 'moneyBackGuaranteeLength'
WHERE u.id = um.profile_id
ORDER BY m.creation_date
) MBG ON MBG.profile_id=u.id
WHERE u.id = 'u162231993'

Need help with a query (using joins)

I have a three tables:
Checkbook table holds what I need to get
Receipts table holds a link to a owner table
Owner table knows what checkbook it is linked to
I need to get the checkbooks only when there are rows in the receipts that are linked to it (through the Owner table).
I don't know exactly how to do this, and it kinda seems circular. This is what I've tried:
SELECT chk.ID, chk.Description FROM tblCheckbook chk
LEFT JOIN tblOwner o
ON r.OwnerID = o.ID
INNER JOIN tblCashReceipts r
ON chk.ID = o.CheckbookID
But sql server complains that "The multi-part identifier "r.OwnerID" could not be bound."
What do I need to do to get this to work?
At the point you do the LEFT JOIN, the definition of r (tblCashReceipts) hasn't been encountered yet. You'll probably want something like:
SELECT chk.ID, chk.Description FROM tblCheckbook chk
LEFT JOIN tblOwner o
ON chk.ID = o.CheckbookID
INNER JOIN tblCashReceipts r
ON o.ID = r.OwnerID
Each join has a on clause that describes the relation. You just have to put the relations with the correct joins.
There is no point in using a left join here as you are using an inner join in the second step. That only causes a larger set for the database to work with to get the same result.
select c.ID, c.Description
from tblCheckBook c
inner join tlbOwner o on o.CheckbookID = c.ID
inner join tblCashReceipts r on r.OwnerID = o.ID
I think you're almost there, you just have your join conditions switched around. Try this:
SELECT chk.ID, chk.Description FROM tblCheckbook chk
LEFT JOIN tblOwner o ON o.CheckbookID = chk.ID
INNER JOIN tblCashReceipts r ON r.OwnerID = o.ID
Or:
SELECT chk.ID, chk.Description FROM tblCheckbook chk
LEFT JOIN tblOwner o ON o.CheckbookID = chk.ID
LEFT JOIN tblCashReceipts r ON r.OwnerID = o.ID
WHERE r.OwnerID IS NOT NULL
So what hapens if there are multiple reciepts for the same Owner? Using this query, you would return a checkbook for each reciept, which may be what you want, but it doesn't sound like it. You may want to throw a DISTINCT on there as well.
Do receipts know what checkbook they belong to?
Join checkbooks through the receipts table.
Owner -> Receipts -> Checkbook

Resources