Select distinct on declared table - sql-server

I need to create concatenated query will get data with checking data in other tables.
Firstly I declared (and filled it) two tables with list of ID I'll check in other tables. On next step (2) I declared new table and filled it values I get by some checking params. This table contains only one column (ID).
After filling if I execute SELECT DISTINCT query from this table I'll get really unique ID. It's OK.
But on next step (3) I declare more one table and filling it by 3 tables. Of course it contains many duplicates. But I must create this query for checking and concatenating. And after that if I execute select distinct h from #NonUnicalConcat it returns many duplicate IDs.
What I did wrong? Where is an error?
USE CurrentBase;
--STEP 1
DECLARE #TempCSTable TABLE(TempTableIDColumn int);
INSERT INTO #TempCSTable VALUES('3'),('4');
DECLARE #TempCVTable TABLE(TempTableIDColumn int);
INSERT INTO #TempCVTable VALUES('2'),('13');
--STEP 2
DECLARE #TempIdTable TABLE(id int);
INSERT INTO #TempIdTable
SELECT TT1.ID
FROM Table1 AS TT1
LEFT OUTER JOIN Table2 ON Table2.ID = TT1.OptionalColumn
LEFT OUTER JOIN Table3 AS TT2 ON TT2.ID = TT1.OptionalColumn
LEFT OUTER JOIN Table4 AS TT3 ON TT3.ID = TT2.OptionalColumn
WHERE TT1.ValueDate > '2020-06-30'
AND TT1.ValueDate < '2020-08-04'
AND TT1.OptBool = '1'
AND TT1.OptBool2 = '0'
AND EXISTS
(
SELECT Table5.ID
FROM Table5
WHERE Table5.ID = TT1.ID
AND Table5.CV IN
(
SELECT TempTableIDColumn
FROM #TempCVTable
)
AND Table5.OptBool = '1'
)
AND EXISTS
(
SELECT Table6.ID
FROM Table6
WHERE Table6.IID = TT3.ID
AND Table6.CS IN
(
SELECT TempTableIDColumn
FROM #TempCSTable
)
);
SELECT distinct * FROM #TempIdTable;--this code realy select distinct
--STEP 3
DECLARE #NonUnicalConcat TABLE(c int, s int, h int);
INSERT INTO #NonUnicalConcat
SELECT TT1.TempTableIDColumn AS cc,
TT2.TempTableIDColumn AS ss,
TT3.id AS hh
FROM #TempCVTable AS TT1,
#TempCSTable AS TT2,
#TempIdTable AS TT3
WHERE NOT EXISTS
(
SELECT HID
FROM OtherBase.dbo.Table1
WHERE HID = TT3.id
AND CS = TT2.TempTableIDColumn
AND CV = TT1.TempTableIDColumn
);
select distinct h from #NonUnicalConcat;--this code return many duplicates

Related

Unable concate NULL value in SQL using CONCAT, COALESCE and ISNULL

I have a query with multiple joins where I want to combine records from two columns into one. If one column is empty then I want to show one column value as result. I tried with CONCAT, COALEASE and ISNULL but no luck. What am I missing here?
My objective is, create one column which has combination of s.Script AS Original and FromAnotherTable from query. Below query runs but throws Invalid column name 'Original' and Invalid column name 'FromAnotherTable'. when I try to use CONCAT, COALEASE or ISNULL .
SQL Query:
SELECT DISTINCT
c.Name AS CallCenter,
LTRIM(RTRIM(s.Name)) Name,
d.DNIS,
s.ScriptId,
s.Script AS Original,
(
SELECT TOP 5 CCSL.Line+'; '
FROM CallCenterScriptLine CCSL
WHERE CCSL.ScriptId = s.ScriptId
ORDER BY ScriptLineId FOR XML PATH('')
) AS FromAnotherTable,
--CONCAT(s.Script, SELECT TOP 5 CCSL.Line+'; ' FROM dbo.CallCenterScriptLine ccsl WHERE ccsl.ScriptId = s.ScriptId ORDER BY ccsl.ScriptLineId xml path(''))
--CONCAT(Original, FromAnotherTable) AS Option1,
--COALESCE(Original, '') + FromAnotherTable AS Option2,
--ISNULL(Original, '') + FromAnotherTable AS Option3,,
r.UnitName AS Store,
r.UnitNumber
FROM CallCenterScript s WITH (NOLOCK)
INNER JOIN CallCenterDNIS d WITH (NOLOCK) ON d.ScriptId = s.ScriptId
INNER JOIN CallCenter c WITH (NOLOCK) ON c.Id = s.CallCenterId
INNER JOIN CallCenterDNISRestaurant ccd WITH (NOLOCK) ON ccd.CallCenterDNISId = d.CallCenterDNISId
INNER JOIN dbo.Restaurant r WITH (NOLOCK) ON r.RestaurantID = ccd.CallCenterRestaurantId
WHERE c.Id = 5
AND (1 = 1)
AND (s.IsDeleted = 0 OR s.IsDeleted IS NULL)
ORDER BY DNIS ASC;
Output:
This works:
DECLARE #Column1 VARCHAR(50) = 'Foo',
#Column2 VARCHAR(50) = NULL;
SELECT CONCAT(#Column1,#Column2);
SELECT COALESCE(#Column2, '') + #Column1
SELECT ISNULL(#Column2, '') + #Column1
So I am not sure what I am missing in my original query.
Look at row 3 in the results you are getting. In your concatenated columns (Option1, 2, 3) you are getting the first script column twice. Not the first one + the second one like you expect.
The reason is because you've aliased your subquery "script" which is the same name as another column in your query, which makes it ambiguous.
Change the alias of the subquery and the problem should go away. I'm frankly surprised your query didn't raise an error.
EDIT: You can't use a column alias in another column's definition in the same level of the query. In other words, you can't do this:
SELECT
SomeColumn AS A
, (Subquery that returns a column) AS B
, A + B --this is not allowed
FROM ...
You can either create a CTE that returns the aliased columns and then concatenate them in the main query that selects from the CTE, or you have to use the original sources of the aliases, like so:
SELECT
SomeColumn AS A
, (Subquery that returns a column) AS B
, SomeColumn + (Subquery that returns a column) --this is fine
FROM ...
I took another approach where instead on creating separate column, I used ISNULL in my subQuery which returns my desired result.
Query:
SELECT DISTINCT
c.Name AS CallCenter,
LTRIM(RTRIM(s.Name)) Name,
d.DNIS,
s.ScriptId,
s.Script AS Original,
(
SELECT TOP 5 ISNULL(CCSL.Line, '')+'; ' + ISNULL(s.Script, '')
FROM CallCenterScriptLine CCSL
WHERE CCSL.ScriptId = s.ScriptId
ORDER BY ScriptLineId FOR XML PATH('')
) AS FromAnotherTable,
r.UnitName AS Store,
r.UnitNumber
FROM CallCenterScript s WITH (NOLOCK)
INNER JOIN CallCenterDNIS d WITH (NOLOCK) ON d.ScriptId = s.ScriptId
INNER JOIN CallCenter c WITH (NOLOCK) ON c.Id = s.CallCenterId
INNER JOIN CallCenterDNISRestaurant ccd WITH (NOLOCK) ON ccd.CallCenterDNISId = d.CallCenterDNISId
INNER JOIN dbo.Restaurant r WITH (NOLOCK) ON r.RestaurantID = ccd.CallCenterRestaurantId
WHERE c.Id = 5
AND (1 = 1)
AND (s.IsDeleted = 0 OR s.IsDeleted IS NULL)
ORDER BY DNIS ASC;
Here's a simplified example using table variables.
Instead of using a subquery for a field, it uses a CROSS APPLY.
And CONCAT in combination with STUFF is used to glue the strings together.
declare #Foo table (fooID int identity(1,1) primary key, Script varchar(30));
declare #Bar table (barID int identity(1,1) primary key, fooID int, Line varchar(30));
insert into #Foo (Script) values
('Test1'),('Test2'),(NULL);
insert into #Bar (fooID, Line) values
(1,'X'),(1,'Y'),(2,NULL),(3,'X'),(3,'Y');
select
f.fooID,
f.Script,
x.Lines,
CONCAT(Script+'; ', STUFF(x.Lines,1,2,'')) as NewScript
from #Foo f
cross apply (
select '; '+b.Line
from #Bar b
where b.fooID = f.fooID
FOR XML PATH('')
) x(Lines)
Result:
fooID Script Lines NewScript
----- ------- ------- -----------
1 Test1 ; X; Y Test1; X; Y
2 Test2 NULL Test2;
3 NULL ; X; Y X; Y

How to properly join when comparing the difference between two tables pertaining to specific fields

I'm having problems writing this query. So I'm comparing a temp table to a table within our database. I want to find any records that don't have the same Case_Number the same Id_Number combination between the two table. The query I am using only provides me one or the other depending on how I join them. If I join by Case_Number, it returns the Case_Number records that do not match between the two tables. If I join by Id_Number, it will return the Id_Numbers that do not match between the two tables.. Is there a way to join by both Case_Number and ID_Number so that the query returns both? I would also like to know if it would be possible for me to include an "If Exist" to the query? Code below
SELECT T1.Case_Number, T1.Id_Number, T1.FirstDate, T1.LastDate, T2.Case_Number, T2.Id_Number, T2.FirstDate, T2.LastDate
FROM dbo.table T
inner join #TempTable T2
on T1.Id_Number = T2.Id_Number
--on T1.Case_Number = T2.Case_Number
where T1.LastDate is null
and T1.Case_Number <> T2.Case_Number
OR T1.Id_number <> T2.Id_Number
Use or in inner join statement
SELECT T1.Case_Number,
T1.Id_Number,
T1.FirstDate,
T1.LastDate,
T2.Case_Number,
T2.Id_Number,
T2.FirstDate,
T2.LastDate
FROM dbo.table T
INNER JOIN #TempTable T2 ON (T1.Id_Number = T2.Id_Number
OR T1.Case_Number = T2.Case_Number)
WHERE T1.LastDate IS NULL
AND T1.Case_Number <> T2.Case_Number
OR T1.Id_number <> T2.Id_Number
This should find both - firsst colum tells you what is the case
(
SELECT 'in Table not in Temp' as R,
T1.Case_Number as 'T1.Case_Number',
T1.Id_Number as 'T1.Id_Number',
T1.FirstDate as 'T1.FirstDate',
T1.LastDate as 'T1.LastDate',
null as 'T2.Case_Number',
null as 'T2.Id_Number',
null as 'T2.FirstDate',
null as 'T2.LastDate'
FROM dbo.table T1
where not exists (
select 1
from #TempTable T2
where T1.Case_Number == T2.CaseNumber
and T1.Id_Number == T2.Id_Number)
)
UNION ALL
(
SELECT 'in temp, not in list' as R
null as 'T1.Case_Number',
null as 'T1.Id_Number',
null as 'T1.FirstDate',
null as 'T1.LastDate',
T2.Case_Number as 'T2.Case_Number',
T2.Id_Number as 'T2.Id_Number',
T2.FirstDate as 'T2.FirstDate',
T2.LastDate as 'T2.LastDate'
FROM #TempTable T2
where not exists (
select 1
from dbo.table T1
where T1.Case_Number == T2.CaseNumber
and T1.Id_Number == T2.Id_Number )
)
Add the T1.LastDate is null - not sure where you want it.
You probably need to tweak the column names , I switched T1/T2 for 2nd statement so column will be the same table all the time, but names have duplicates.

How to use table valued function as part of select statement in sql server

I have a select statement which returns a table. I want to select a table valued function as a part of that select statement, which also returns a table.. How to do that.
This is my select code which returns a table
SELECT
dbo.TC_User.JobTitle, dbo.TC_User.UserID,
dbo.TC_User.LocalID, dbo.TC_User.NokiaID, dbo.TC_User.NameCN,
dbo.TC_User.职阶 as EmployeeGroup,
dbo.TC_User2.LockDateID, dbo.TC_User.StartDate,
dbo.TC_User.EndDate, dbo.TC_User.StartDateN,
dbo.TC_User.聘用前工号, dbo.TC_User.NoCheckFlag,
dbo.GetGroupPath2('465') AS Path
FROM
dbo.TC_User
INNER JOIN
dbo.TC_User2 ON dbo.TC_User.UserID = dbo.TC_User2.UserID
WHERE
(dbo.TC_User.UserID IN (SELECT UserID
FROM dbo.TC_User
WHERE (GroupID IN (SELECT GroupID
FROM dbo.VSGetSubGroupTab(10, 1) AS VSGetSubGroupTab))))
This is what I want
SELECT
dbo.TC_User.JobTitle, dbo.TC_User.UserID,
dbo.GetGroupPath2Clone('465') as grouppath,
dbo.TC_User.LocalID, dbo.TC_User.NokiaID, dbo.TC_User.NameCN,
dbo.TC_User.职阶 as EmployeeGroup,
dbo.TC_User2.LockDateID, dbo.TC_User.StartDate,
dbo.TC_User.EndDate, dbo.TC_User.StartDateN,
dbo.TC_User.聘用前工号, dbo.TC_User.NoCheckFlag,
dbo.GetGroupPath2('465') AS Path
FROM
dbo.TC_User
INNER JOIN
dbo.TC_User2 ON dbo.TC_User.UserID = dbo.TC_User2.UserID
WHERE
(dbo.TC_User.UserID IN (SELECT UserID
FROM dbo.TC_User
WHERE (GroupID IN (SELECT GroupID
FROM dbo.VSGetSubGroupTab(10, 1) AS VSGetSubGroupTab))))
dbo.GetGroupPath2Clone('465') as grouppath, is the table valued function which I want to call. How to do that?
the dbo.GetGroupPath2 looks like a scalar function. However, if it is a table function then you need to place it in the join list.
SELECT
dbo.TC_User.JobTitle, dbo.TC_User.UserID,
dbo.TC_User.LocalID, dbo.TC_User.NokiaID, dbo.TC_User.NameCN,
dbo.TC_User.职阶 as EmployeeGroup,
dbo.TC_User2.LockDateID, dbo.TC_User.StartDate,
dbo.TC_User.EndDate, dbo.TC_User.StartDateN,
dbo.TC_User.聘用前工号, dbo.TC_User.NoCheckFlag,
tf.yourfield1, tf.yourfield2, ...etc.
FROM
dbo.TC_User
join dbo.GetGroupPath2('465') AS tf on tf.yourkey=somekeys
INNER JOIN
dbo.TC_User2 ON dbo.TC_User.UserID = dbo.TC_User2.UserID
WHERE
(dbo.TC_User.UserID IN (SELECT UserID
FROM dbo.TC_User
WHERE (GroupID IN (SELECT GroupID
FROM dbo.VSGetSubGroupTab(10, 1) AS VSGetSubGroupTab))))
to create the table function:
CREATE FUNCTION [dbo].GetGroupPath2
(
#Parm varchar(10)
)
Returns Table
As
Return (
Select yourfield1, yourfield2
From yourTable
where [yourKey] = #Parm
)

three tables join is not giving desired output

I have three tables:
1: Station_Details (master data table)
2: RF_Details
3: WL_Details
As mention in below image.
I need a to take data from all three table in to a output table
Master data from Station_details and other data from RF and WL tables.
If RF_Details and WL_Details tables are having same station id and same DateTime then in output table both rows details will show in one row.
If DateTime are different then it will appear in different rows.
I tried this sql query but I am not getting the same output like OUTPUT Table.
select rf.StationID, st.stationname, st.state,rf.rf,rf.cum-rf,wl.wl,DataTime
from [RF_Details] rf
join [WL_Details] wl
join Station_Details st
on rf.StationID = wl.StationId and
rf.DataRecieved=wl.DataRecieved and
st.stationid =rf.stationid and
st.stationid = wl.stationid;
But it didn't give the right number of rows and output.
Please help me for the same.
You should always put the join conditions along with the join itself. Also, adding the INNER is a practice I follow to ensure no extra records are returned.
SELECT rf.StationID, st.stationname, st.state, wl.DataRecieved, wl.waterlevel1,
rf.dailyrainfall, rf.cumrainfall
FROM [RF_Details] rf
INNER JOIN [WL_Details] wl
ON rf.StationID = wl.StationId AND
rf.DataRecieved=wl.DataRecieved
INNER JOIN Station_Details st
ON st.stationid =rf.stationid AND
st.stationid = wl.stationid;
declare #station_details table(id int, station_id varchar(10),station_name varchar(10),state varchar(10))
declare #rf_details table (id int, station_id varchar(10),rf int, cum_rf int, dt dateTIME)
declare #wl_details table (id int, station_id varchar(10),wl int,dt datetime)
insert into #station_details values
(1,'DEL-NDL','NDL','DEL'),
(2,'UP-LKO','LKO','UP'),
(3,'MP-BHP','BHP','MP'),
(4,'MHR-MUM','MUM','MHR')
INSERT INTO #RF_DETAILS VALUES
(1,'DEL-NDL',42,435,'2016-06-13 05:15:00'),
(2,'UP-LKO',0,501,'2016-06-13 05:15:00'),
(3,'MP-BHP',20,350,'2016-06-13 05:15:00'),
(4,'MHR-MUM',30,200,'2016-06-13 05:15:00'),
(5,'MHR-MUM',15,100,'2016-06-14 05:15:00'),
(6,'UP-LKO',50,350,'2016-06-13 05:15:00')
INSERT INTO #WL_DETAILS VALUES
(1,'DEL-NDL',25,'2016-06-13 05:15:00'),
(2,'UP-LKO',35,'2016-06-13 05:30:00'),
(3,'MP-BHP',46,'2016-06-13 05:45:00'),
(4,'MHR-MUM',20,'2016-06-13 05:15:00'),
(5,'MHR-MUM',15,'2016-06-14 05:15:00'),
(6,'UP-LKO',60,'2016-06-13 05:15:00')
;with cte as
(
SELECT case
when rf.dt = wl.dt then 'Y'
else 'N'
end as matched,
rf.id as id,rf.station_id as stationid,rf.rf as rf , rf.cum_rf as cumrf , rf.dt as rfdt,
wl.id as wlid, wl.station_id ,wl.wl ,wl.dt as wldte,
rf.station_id as station,rf.dt as rfdte
FROM #RF_DETAILS RF
JOIN #WL_DETAILS WL ON rf.id = wl.id and RF.STATION_ID = WL.STATION_ID
)
select row_number() over (order by s.id) newid,
s.id,s.station_id,sd.station_name,sd.state,s.rf,s.cumrf,s.wl,
case
when s.srce = 'L' then s.rfdte
else s.wldte
end as 'Date'
from
(
select 'L' as srce,cte.id,cte.station_id,cte.rf,cte.cumrf, cte.wl as wl, cte.rfdte,cte.wldte from cte where cte.matched = 'Y'
union
select 'L' as srce,cte.id,cte.station_id,cte.rf,cte.cumrf, null as wl, cte.rfdte,cte.wldte from cte where cte.matched = 'N'
union all
select 'R' as srce,cte.id * 10,cte.station_id,null,null, cte.wl as wl, cte.rfdte,cte.wldte from cte where cte.matched = 'N'
) s
join #station_details sd on sd.station_id = s.station_id
order by s.id
You should redesign your database: right now you have a secondary key in RF_Details and WL_Details - DateTime. Which plays a role of a foreign key between them. Which is no good and will continue confusing you every time you need to join those table or collect corresponding data.
There should be another table like Station_Records which will store a row per every record for that station: (id, station_id, record_date_time). RF and WL rows if any should refer this table instead of referring Station_Details with station_id and one another with datetime.
With current structure you need to do full join of RF and WL to get both: matching by datetime - in same row, not matching - in separate rows.
select sd.station_name, Station_Records.*
from Station_Details sd
inner join
(
select
IsNull(rf.station_id, wl.station_id) station_id,
IsNull(rf.DataRecieved, wl.DataRecieved) DataRecieved,
rf.rf, rf.cum-rf, wl.wl
from [RF_Details] rf
full join [WL_Details] wl
on wl.station_id = rf.station_id
and wl.DataRecieved = rf.DataRecieved
) Station_Records
on Station_Records.station_ud = sd.station_id
concrete implementation may consist of OUTER APPLY or even be without any subqueries - it does not really matter currently.
Modify your table structure and you will always know all matching records:
select
sd.station_id, sd.station_name,
sr.DataRecieved
rf.rf, rf.cum-rf,
wl.wl
from Station_Details sd
inner join Station_Records sr
on sr.station_id = sd.station_id
left join RF_Details rf
on rf.record_id = sr.record_id
left join WL_Details wl
on wl.record_id = sr.record_id

Conditional JOIN Statement SQL Server

Is it possible to do the following:
IF [a] = 1234 THEN JOIN ON TableA
ELSE JOIN ON TableB
If so, what is the correct syntax?
I think what you are asking for will work by joining the Initial table to both Option_A and Option_B using LEFT JOIN, which will produce something like this:
Initial LEFT JOIN Option_A LEFT JOIN NULL
OR
Initial LEFT JOIN NULL LEFT JOIN Option_B
Example code:
SELECT i.*, COALESCE(a.id, b.id) as Option_Id, COALESCE(a.name, b.name) as Option_Name
FROM Initial_Table i
LEFT JOIN Option_A_Table a ON a.initial_id = i.id AND i.special_value = 1234
LEFT JOIN Option_B_Table b ON b.initial_id = i.id AND i.special_value <> 1234
Once you have done this, you 'ignore' the set of NULLS. The additional trick here is in the SELECT line, where you need to decide what to do with the NULL fields. If the Option_A and Option_B tables are similar, then you can use the COALESCE function to return the first NON NULL value (as per the example).
The other option is that you will simply have to list the Option_A fields and the Option_B fields, and let whatever is using the ResultSet to handle determining which fields to use.
This is just to add the point that query can be constructed dynamically based on conditions.
An example is given below.
DECLARE #a INT = 1235
DECLARE #sql VARCHAR(MAX) = 'SELECT * FROM [sourceTable] S JOIN ' + IIF(#a = 1234,'[TableA] A ON A.col = S.col','[TableB] B ON B.col = S.col')
EXEC(#sql)
--Query will be
/*
SELECT * FROM [sourceTable] S JOIN [TableB] B ON B.col = S.col
*/
You can solve this with union
select a, b
from tablea
join tableb on tablea.a = tableb.a
where b = 1234
union
select a, b
from tablea
join tablec on tablec.a = tableb.a
where b <> 1234
I disagree with the solution suggesting 2 left joins. I think a table-valued function is more appropriate so you don't have all the coalescing and additional joins for each condition you would have.
CREATE FUNCTION f_GetData (
#Logic VARCHAR(50)
) RETURNS #Results TABLE (
Content VARCHAR(100)
) AS
BEGIN
IF #Logic = '1234'
INSERT #Results
SELECT Content
FROM Table_1
ELSE
INSERT #Results
SELECT Content
FROM Table_2
RETURN
END
GO
SELECT *
FROM InputTable
CROSS APPLY f_GetData(InputTable.Logic) T
I think it will be better to think about your query in a different way and treat them more like sets.
I do believe if you make two separate queries then join them using UNION, It will be much better in performance and more readable.

Resources