Write subquery in xml.exist() - sql

I have a table with one column:
IF OBJECT_ID('tempdb..#tmp') IS NOT NULL DROP TABLE #tmp
CREATE TABLE #tmp
(
data XML
)GO
with one record:
INSERT INTO #tmp
VALUES ( N'<RelevanExpertXML><Tel><RelevanExpert>1</RelevanExpert></Tel><Tel><RelevanExpert>2</RelevanExpert></Tel></RelevanExpertXML>')
and another tale with one column
CREATE TABLE #tmp2
(
id int
)
GO
and i want to write this query:
select *
from #temp
where xml.exist('/RelevanExpertXML/Tel/RelevanExpert[(text()) = [select id from #temp2]]') = 1
in fact i want to write sub query in exist(), but i get error, and also i can't change from clause and select list, only i can change where clause.
thanks for help.

you can use this query:
select *
from #tmp
where exists
(
select *
from #tmp2 as t
where
#tmp.data.exist('/RelevanExpertXML/Tel/RelevanExpert[(text()) = sql:column("t.id")]') = 1
)
but it will return you the whole xml. If you want to split xml by rows, you have to use nodes() function in the from clause.

You can write
select *
from #tmp, #temp2
where data.exist('/RelevanExpertXML/Tel/RelevanExpert[text()] = sql:column("id")')=1
But I don't think it will give you the results you're after.
You may be after something more like
select t.r.value('.','int')
from #tmp temp
cross apply data.nodes('/RelevanExpertXML/Tel/RelevanExpert') t(r)
inner join #temp2 t2 on t.r.value('.','int') = t2.id

Related

SQL: JOIN problem using temp tables and one column

I am created two temp tables in which TABLE1 contains all the items and TABLE2 only has the partial list of TABLE1. How can I find out which parts TABLE 1 has that TABLE2 doesn't have or vice versa? Please keep in mind, the temp table only has one column due to the DISTINCT statement.
I do have to use Joins but my thought is if I JOIN on the individual columns of each table and then in the Where clause state that e.g. column 1 is not equal column 2, it's contradicting.
IF EXISTS (
SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = Object_id(N'tempdb..#TABLE1')
)
BEGIN
DROP TABLE #TABLE1
END
IF EXISTS (
SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = Object_id(N'tempdb..#TABLE2')
)
BEGIN
DROP TABLE #TABLE2
END
------------------------------------------------
select distinct 1.parts as #TABLE1 from List1 1 --- MAIN LIST
select distinct 2.parts as #TABLE2 from List2 2 --- ADDITIONAL LIST
select *
from #TABLE2 left join
#TABLE1
on 2.parts = 1.parts
where 2.parts <> 1.parts
Your where clause is undoing the left join. I would recommend not exists:
select t1.*
from #table1 t1
where not exists (select 1 from #table2 t2 where t2.parts = t1.parts);

Insert into each column of a table values based on conditions

I have a table of products like this:
I want to delete duplicate rows in this table and use the Ids in other tables, so I used a temporary table to add just the Ids to delete and the Ids to keep:
-- create tmp table
create table #tmp (ProductId_ToKeep int, ProductId_ToDelete int);
-- collect the Products that have a lower id with the same name in the temp table
insert into #tmp (ProductId_ToKeep)
select [ProductId]
from dbo.[Product] t1
where exists
(
select 1
from dbo.[Product] t2
where t2.name = t1.name
and t2.[ProductId] > t1.[ProductId]
);
-- collect the Products that have a higher id with the same name in the temp table
insert into #tmp (ProductId_ToDelete)
select [ProductId]
from dbo.[Product] t1
where exists
(
select 1
from dbo.[Product] t2
where t2.name = t1.name
and t2.[ProductId] < t1.[ProductId]
);
select * from #tmp
After getting what I have in my temp table, I got this result:
I'm asking if any can one help me to put the Ids in each column as I want.
If I followed you correctly, you could use a window function to feed the transcodification table in a single query, like so:
insert into #tmp (ProductId_ToKeep, ProductId_ToDelete)
select *
from (
select
ProductId ProductId_ToDelete,
min(ProductId) over(partition by name) ProductId_ToKeep
from dbo.[Product]
) t
where ProductId_ToDelete != ProductId_ToKeep
The inner query pulls out the smallest ProductId for the given name; the outer query filters on record that should be deleted (ie whose ProductId is not the minimum ProductId for the same name).

SQL Update Multiple Rows with Count from another Table

Suppose I have two tables. One table, tbl1, is "long" and non-aggregated. The structure is as follows:
Software_Name:
Word
PowerPoint
PowerPoint
Excel
Word
PowerPoint
In a second Table, tbl2, I want to summarize the data from the first table, namely the count of Software. The second Table will have a structure like:
Software_Name: Count:
Word 2
PowerPoint 3
Excel 1
I have tried:
update tbl2
set count =
(select count(software_name)
from tbl1
group by software_name
where tbl1.software_name = tbl2.software_name)
from tbl1
I get a result inserted into the proper column, but it is not the proper value. It is the sum of all values, in this case 5. I have included the where clause because in my tbl1 I have many more software_names than am interested in counting in tbl2.
UPDATE
I am using Teradata Aster for this project. I have been looking at the Aster documentation for the UPDATE command and came across this:
UPDATE [ ONLY ] table
SET column = expression [, ...]
[ FROM fromlist ]
[ WHERE condition | WHERE CURRENT OF cursor_name ];
In reading about the fromlist, I came across this bit of information:
Note that the target table must not appear in the fromlist unless you intend a
self-join (in which case it must appear with an alias in the fromlist).
You want a correlated subquery:
update tbl2
set count = (select count(*) from tbl1 where tbl1.software_name = tbl2.software_name);
Not sure what DBMS you're using but in SQL Server I would recommend a CROSS APPLY with example below...
update t2
set t2.[Count] = t1.[Count]
from t2
cross apply (
select count(*) AS [Count]
from t1
where t1.Software_name = t2.Software_name
) AS t1
You can read more about the APPLY operator here: https://www.mssqltips.com/sqlservertip/1958/sql-server-cross-apply-and-outer-apply/
You can try using the CTE as below:
DECLARE #TABLE1 AS TABLE (Software_Name VARCHAR(100))
INSERT INTO #TABLE1
SELECT 'Word'
UNION ALL
SELECT 'PowerPoint'
UNION ALL
SELECT 'PowerPoint'
UNION ALL
SELECT 'Excel'
UNION ALL
SELECT 'Word'
UNION ALL
SELECT 'PowerPoint'
DECLARE #TABLE2 AS TABLE (Software_Name VARCHAR(100),Cnt INT)
INSERT INTO #TABLE2 (Software_Name)
SELECT DISTINCT Software_Name FROM #TABLE1
;WITH CTE AS
(
SELECT
COUNT(T1.Software_Name) AS Cnt
,T1.Software_Name
FROM #TABLE2 T2
INNER JOIN #TABLE1 T1 ON T1.Software_Name = T2.Software_Name
GROUP BY
T1.Software_Name
)
UPDATE T2
SET
T2.Cnt = C.Cnt
FROM #TABLE2 T2
INNER JOIN CTE C ON C.Software_Name = T2.Software_Name
SELECT * FROM #TABLE2
NOTE: I am assuming you are using SQL Server. Also i am posting it as an answer as i dont have desired reputation to comment.
hope it helps!

how to fetch all the records from one table as XML datatype to another column of second table

I want to fetch all the records from one table as XML datatype and store it in another column of second table.
I have two columns that will match these two tables for joining, reportid and exchange.
Should I have to use ID logic or please help me with this logic.
sample :
DECLARE #VAL XML
SET #VAL = (
SELECT
[ID] AS [ID]
,[EventType] AS [EventType]
,[ClientMsgID] AS [ClientMsgID]
,[SessionID] AS [SessionID]
,[Protocol] AS [Protocol]
FROM TableA O
JOIN Tableb T
ON O.[ReportID] = T.ReportID
where o.[exchange] = t.exchange
FOR XML PATH ('row'))
insert into TableC
select ID,record_no,#VAL,null,getdate()
from TableA
You have not provided enough details on your table design.
If I understood correctly, you want to update table with XML from another table, for this you can try like following.
UPDATE ST
SET ColumnToStoreXml=(select * from FristTable FT
where FT.ColumnToMatch=ST.ClumnToMatch for xml PATH ('row') )
FROM SecondTable ST
Edit: After the update in the question.
If you want to insert into a new table, try like following.
INSERT INTO tablec
SELECT id,
record_no,
(SELECT [id] AS [ID],
[eventtype] AS [EventType],
[clientmsgid] AS [ClientMsgID],
[sessionid] AS [SessionID],
[protocol] AS [Protocol]
FROM tablea O
JOIN tableb T
ON O.[reportid] = T.reportid
WHERE o.[exchange] = t.exchange
AND O.id = T1.id
FOR xml path ('row')),
Getdate()
FROM tablea T1
Note: It's always a good practice is to use column names in your insert like
insert into tablec(col1,col2,col3)
select col1,col2,col3 from sometable

SQL select from column where column equals table variable?

I'm a serious SQL noob so any help is appreciated. I'm having a hard time even explaining what I'm trying to do so I'll lay out what I have so far:
DECLARE #UserIDInt table (ID int);
INSERT into #UserIDInt
SELECT UserId
FROM [LcsCDR].[dbo].[Users]
WHERE [LcsCDR].[dbo].[Users].[UserUri] LIKE '%example';
SELECT *
FROM [LcsCDR].[dbo].[SessionDetails]
WHERE [LcsCDR].[dbo].[SessionDetails].[User1Id] = #UserIDInt;
"DECLARE #UserIDInt table (ID int);"
This creates my variable with a column called "ID"
INSERT into #UserIDInt
SELECT UserId
FROM [LcsCDR].[dbo].[Users]
WHERE [LcsCDR].[dbo].[Users].[UserUri] LIKE '%example';
This adds numeric values into the ID column based on whether or not the WHERE statement matched
SELECT *
FROM [LcsCDR].[dbo].[SessionDetails]
WHERE [LcsCDR].[dbo].[SessionDetails].[User1Id] = #UserIDInt;
This is where I am lost. I am trying to return all rows from [LcsCDR].[dbo].[SessionDetails] if the column [LcsCDR].[dbo].[SessionDetails].[User1Id] matches anything in my variable. The problem (I think) I'm having is that SQL can't look within the variable's column to find multiple values. Basically, the ID column in my variable #UserIDInt will contain a bunch of numeric values.
How do I perform the final SELECT statement and have SQL return all results if [LcsCDR].[dbo].[SessionDetails].[User1Id] matches anything within my #UserIDInt.ID column?
I am using SQL Server 2014.
Apologies if I explained it badly. Not sure how else to ask the question :)
using inner join:
select sd.*
from [lcscdr].[dbo].[sessiondetails] sd
inner join #useridint i
on i.id = sd.user1id;
or using exists():
select sd.*
from [lcscdr].[dbo].[sessiondetails] sd
where exists (
select 1
from #useridint i
where i.id = sd.user1id
);
or using in():
select sd.*
from [lcscdr].[dbo].[sessiondetails] sd
where sd.user1id in (
select id
from #useridint i
);
rextester demo: http://rextester.com/UVCB28056
Use EXISTS:
SELECT T1.*
FROM [lcscdr].[dbo].[sessiondetails] T1 WHERE EXISTS (
SELECT 1
FROM #useridint T2
WHERE T2.id = T1.user1id
);