Multiple JOINs with same column SQL Server - sql-server

I have to select id from GraphNodes whereas same id exists in GraphEdges in two columns i.e. Source_Node and Target_Node. The structure of tables are as follows:
GraphNodes
+---+---------+-------------------+------------+-----------+
| id | Node_ID | Node | Node_Label | Node_Type |
+---+---------+-------------------+------------+-----------+
| 1 | 677 | Nuno Vasconcelos | Author | 1 |
| 2 | 1359 | Peng Shi | Author | 1 |
| 3 | 6242 | Z. Q. Shi | Author | 1 |
+----+---------+------------------+------------+-----------+
GraphEdges
+------------+------------------+-------------+------------------+------+-----------+
|Source_Node | Source_Node_Type | Target_Node | Target_Node_Type | Year | Edge_Type |
+------------+------------------+-------------+------------------+------+-----------+
| 1 | 1 | 10965 | 2 | 2005 | 1 |
| 1 | 1 | 10179 | 2 | 2007 | 1 |
| 1 | 1 | 10965 | 2 | 2007 | 1 |
+------------+------------------+-------------+------------------+------+-----------+
I have shown only 3 rows for both tables just to get an idea of table's structures. I have used query as:
SELECT GN.id as Node_ID,
COUNT(DISTINCT(CONCAT(GE.Source_Node, '-', GE.Target_Node)))
AS Mutual_Links -- OR Node_Degree
FROM GraphEdges GE
JOIN GraphNodes GN ON GN.id = GE.Source_Node --How to JOIN this
AND GN.id = GE.Target_Node --How to JOIN this
WHERE (Source_Node IN (SELECT id FROM GraphNodes
WHERE id BETWEEN 1 AND 510)
AND Edge_Type IN (1, 2, 3))
OR (Target_Node IN (SELECT id FROM GraphNodes
WHERE id BETWEEN 1 AND 510)
AND Edge_Type IN (1, 2, 3))
GROUP BY GN.id
I want output in the form:
+--------+-------------+
|Node_ID | Mutual_Links|
+--------+-------------+
| 1 | 31 |
| 2 | 23 |
| 3 | 12 |
| ... | ... |
+--------+-------------+
The issue is that how to join GraphEdges with GraphNodes that I can get id OR Node_ID form GraphNodes and COUNT DISTINCT Mutual_Links from GraphEdges.

how about something like this
;with thedata ( id, MutualLinks )
as (Select id, MutualLinks = count(*) from [dbo].[GraphNodes]
inner join [dbo].[GraphEdges] on Source_node = node_id
group by id
union all
Select id, MutualLinks = count(*) from [dbo].[GraphNodes]
inner join [dbo].[GraphEdges] on target_node = node_id
group by id )
Select id, total = sum(MutualLinks)
from thedata
group by id

Related

Assign value into specific column using Pivot or Unpivot

I have a table with below structure:
+-------+-----------+--------+----------+--------+
| RefNo | TranType | Code | Remarks | Amount |
+-------+-----------+--------+----------+--------+
| 1 | BD | 400201 | abcc dfr | 200 |
| 1 | BD | 400202 | abcc dfr | 200 |
| 2 | BD | 400204 | defrt | 300 |
| 2 | BD | 400205 | defrt | 300 |
+-------+-----------+--------+----------+--------+
I need to transpose these values to the below format:
+-------+--------+--------+----------+----------+--------+
| RefNo | Code1 | Code2 | TranType | Remarks | Amount |
+-------+--------+--------+----------+----------+--------+
| 1 | 400201 | 400202 | BD | abcc dfr | 200 |
| 2 | 400204 | 400205 | BD | defrt | 300 |
+-------+--------+--------+----------+----------+--------+
You don't need to use PIVOT, you can do it using a simple query.
SELECT t1.refno,
t1.code AS Code1,
t2.code AS Code2,
t1.trantype,
t1.amount
FROM #table t1
INNER JOIN #table t2
ON t1.refno = t2.refno
AND T1.code < T2.code
Online Demo
You can try the following query.
;WITH Tab (RefNo,Code,TranType,Remarks,Amount,rowno)
AS
(SELECT T.RefNo
, T.Code
,TranType
,Remarks
,Amount
, RN = ROW_NUMBER() OVER (PARTITION BY T.RefNo ORDER BY T.Code )
FROM Table1 T)
SELECT RefNo,Code1 = MAX( CASE WHEN N.rowno=1 THEN N.Code ELSE 0 END ),
Code2 = MAX( CASE WHEN N.rowno=2 THEN N.Code ELSE 0 END ) ,
TranType,Remarks,Amount FROM Tab n
GROUP BY N.RefNo,TranType,Remarks,Amount

Getting duplicates with additional information

I've inherited a database and I'm having trouble constructing a working SQL query.
Suppose this is the data:
[Products]
| Id | DisplayId | Version | Company | Description |
|---- |----------- |---------- |-----------| ----------- |
| 1 | 12345 | 0 | 16 | Random |
| 2 | 12345 | 0 | 2 | Random 2 |
| 3 | AB123 | 0 | 1 | Random 3 |
| 4 | 12345 | 1 | 16 | Random 4 |
| 5 | 12345 | 1 | 2 | Random 5 |
| 6 | AB123 | 0 | 5 | Random 6 |
| 7 | 12345 | 2 | 16 | Random 7 |
| 8 | XX45 | 0 | 5 | Random 8 |
| 9 | XX45 | 0 | 7 | Random 9 |
| 10 | XX45 | 1 | 5 | Random 10 |
| 11 | XX45 | 1 | 7 | Random 11 |
[Companies]
| Id | Code |
|---- |-----------|
| 1 | 'ABC' |
| 2 | '456' |
| 5 | 'XYZ' |
| 7 | 'XYZ' |
| 16 | '456' |
The Versioncolumn is a version number. Higher numbers indicate more recent versions.
The Company column is a foreign key referencing the Companies table on the Id column.
There's another table called ProductData with a ProductId column referencing Products.Id.
Now I need to find duplicates based on the DisplayId and the corresponding Companies.Code. The ProductData table should be joined to show a title (ProductData.Title), and only the most recent ones should be included in the results. So the expected results are:
| Id | DisplayId | Version | Company | Description | ProductData.Title |
|---- |----------- |---------- |-----------|------------- |------------------ |
| 5 | 12345 | 1 | 2 | Random 2 | Title 2 |
| 7 | 12345 | 2 | 16 | Random 7 | Title 7 |
| 10 | XX45 | 1 | 5 | Random 10 | Title 10 |
| 11 | XX45 | 1 | 7 | Random 11 | Title 11 |
because XX45 has 2 "entries": one with Company 5 and one with Company 7, but both companies share the same code.
because 12345 has 2 "entries": one with Company 2 and one with Company 16, but both companies share the same code. Note that the most recent version of both differs (version 2 for company 16's entry and version 1 for company 2's entry)
ABC123 should not be included as its 2 entries have different company codes.
I'm eager to learn your insights...
Based on your sample data, you just need to JOIN the tables:
SELECT
p.Id, p.DisplayId, p.Version, p.Company, d.Title
FROM Products AS p
INNER JOIN Companies AS c ON p.Company = c.Id
INNER JOIN ProductData AS d ON d.ProductId = p.Id;
But if you want the latest one, you can use the ROW_NUMBER():
WITH CTE
AS
(
SELECT
p.Id, p.DisplayId, p.Version, p.Company, d.Title,
ROW_NUMBER() OVER(PARTITION BY p.DisplayId,p.Company ORDER BY p.Id DESC) AS RN
FROM Products AS p
INNER JOIN Companies AS c ON p.Company = c.Id
INNER JOIN ProductData AS d ON d.ProductId = p.Id
)
SELECT *
FROM CTE
WHERE RN = 1;
sample fiddle
| Id | DisplayId | Version | Company | Title |
|----|-----------|---------|---------|----------|
| 5 | 12345 | 1 | 2 | Title 5 |
| 7 | 12345 | 2 | 16 | Title 7 |
| 10 | XX45 | 1 | 5 | Title 10 |
| 11 | XX45 | 1 | 7 | Title 11 |
If i understood you correctly, you can use CTE to find all the duplicated rows from your table, then you can just use SELECT from CTE and even add more manipulations.
WITH CTE AS(
SELECT Id,DisplayId,Version,Company,Description,ProductData.Title
RN = ROW_NUMBER()OVER(PARTITION BY DisplayId, Company ORDER BY p.Id DESC)
FROM dbo.YourTable1
)
SELECT *
FROM CTE
Try this:
SELECT b.ID,displayid,version,company,productdata.title
FROM
(select A.ID,a.displayid,version,a.company,rn,a.code, COUNT(displayid) over (partition by displayid,code) cnt from
(select Prod.ID,displayid,version,company,Companies.code, Row_number() over (partition by displayid,company order by version desc) rn
from Prod inner join Companies on Prod.Company = Companies.id) a
where a.rn=1) b inner join productdata on b.id = productdata.id where cnt =2
You have to first get the current version and then you see how many times the DisplayID + Code show-up. Then based on that you can select only the ones that have a count greater than one. You can then INNER JOIN ProductData on the final query to get the Title.
WITH
MaxVersion AS --Get the current versions
(
SELECT
MAX(Version) AS Version,
DisplayID,
Company
FROM
#TmpProducts
GROUP BY
DisplayID,
Company
)
,CTE AS
(
SELECT
p.DisplayID,
c.Code,
COUNT(*) AS RowCounter
FROM
#TmpProducts p
INNER JOIN
#TmpCompanies c
ON
c.ID = p.Company
INNER JOIN
MaxVersion mv
ON
mv.DisplayID = p.DisplayID
AND mv.Version = p.Version
AND mv.Company = p.Company
GROUP BY
p.DisplayID,
c.Code
)
SELECT
p.*
FROM
#TmpProducts p
INNER JOIN
CTE c
ON
c.DisplayID = p.DisplayID
INNER JOIN
MaxVersion mv
ON
mv.DisplayID = p.DisplayID
AND mv.Company = p.Company
AND mv.Version = p.Version
WHERE
c.RowCounter > 1

Perform an aggregate function on an expression containing an aggregate or a subquery

Can't perform any kind of aggregate function. I have 2 tables with entities and one table which contain transactions for every entity.
#qui
+--------+------------+
| idx | nbn |
+--------+------------+
| 44444 | 152357 |
| 55555 | 778852 |
| 66666 | 776856 |
+--------+------------+
#zea
+--------+------------+
| idx | nbn |
+--------+------------+
| 11111 | 159357 |
| 22222 | 753852 |
| 33333 | 745856 |
+--------+------------+
#trx
+--------+------------+---------+--------+
| idx | nbn |trx_amt |date |
+--------+------------+---------+--------+
| 11111 | 159357 |100 |01-01-16|
| 22222 | 753852 |200 |04-04-16|
| 33333 | 745856 |300 |11-05-16|
+--------+------------+---------+--------+
My query:
select
date
,qui_co = count (case when trx.idx in (select idx from qui) then trx_amt
,zea_co = count (case when trx.idx in (select idx from zea) then trx_amt
end)
from
trx
inner join (select idx from qui
union
select idx from zea) xxx
on trx.idx = xxx.idx
group by date
Any idea for some other solution ?
You should be able to do this with left joins:
select [date], count(q.idx), count(z.idx)
from trx t
left join qui q on t.idx=q.idx
left join zea z on t.idx=z.idx
group by [date]

SQL Server selecting minimum value from duplicates

From the below table how can I pull the minimum value from CODE column for each duplicated USERID.
USER_ID | CODE | ROW_ID | NAME
1111111111 | -0.118 | 1 | USER1
1111111111 | 91.528 | 2 | USER2
2222222222 | 92.41 | 3 | USER3
2222222222 | 10.85 | 4 | USER4
2222222222 | 56.02 | 5 | USER5
3333333333 | -0.324 | 6 | USER6
3333333333 | 12.78 | 7 | USER7
4444444444 | 0.0002 | 8 | USER8
4444444444 | -1.324 | 9 | USER9
5555555555 | 93.598 | 10 | USER11
5555555555 | 101.35 | 11 | USER12
5555555555 | -5.425 | 12 | USER13
I tried the below query, but getting only the USER_ID and MIN(CODE). How to get the entire row as below said output?
SELECT USER_ID, min(CODE) minCODE
FROM TABLE1
GROUP BY USER_ID
The output should be:
USER_ID | CODE | ROW_ID | NAME
1111111111 | -0.118 | 1 | USER1
2222222222 | 10.85 | 4 | USER4
3333333333 | -0.324 | 6 | USER6
4444444444 | -1.324 | 9 | USER9
5555555555 | -5.425 | 12 | USER13
try this
;with a as (
SELECT
*
,ROW_NUMBER() OVER(PARTITION BY USER_ID ORDER BY CODE) r
FROM TABLE1
)
SELECT *
FROM a
WHERE r = 1
You are almost there, use result from your query to get another columns data
;WITH minvalue AS
(
SELECT USER_ID
, MIN(CODE) AS MinCode ยจ
FROM TABLE1
GROUP BY USER_ID
)
SELECT t.USER_ID
, t.CODE
, t.ROW_ID
, t.NAME
FROM TABLE1 t
INNER JOIN minvalue mv ON mv.USER_ID = t.USER_ID
AND mv.MinCode = t.CODE
You'd need to run another pass with your initial query as a derived table:
select
USER_ID, CODE, ROW_ID, NAME
from
TABLE1
inner join
(SELECT USER_ID, min(CODE) minCODE
FROM TABLE1
GROUP BY USER_ID) derived TABLE1.USER_ID on derived.USER_ID
This way, you'll get your MIN, then you use that to grab the rest of the data from the table.

TSQL pivot issue

Hello I have a temp table (#tempResult) that contains results like the following...
-----------------------------------------
| DrugAliasID | Dosage1 | Unit1 | rowID |
-----------------------------------------
| 322 | 10 | MG | 1 |
| 322 | 50 | ML | 2 |
| 441 | 20 | ML | 3 |
| 443 | 15 | ML | 4 |
-----------------------------------------
I'm looking to get the results to be like the following, pivoting the rows that have the same DrugAliasID.
--------------------------------------------------
| DrugAliasID | Dosage1 | Unit1 | Dosage2 | Unit2 |
--------------------------------------------------
| 322 | 10 | MG | 50 | ML |
| 441 | 20 | ML | NULL | NULL |
| 443 | 15 | ML | NULL | NULL |
--------------------------------------------------
So far I have a solution that isn't using pivot. I'm not too good with pivot and was wondering if anyone knew how to use it in this scenario. Or solve it some other way. Thanks
SELECT
tr.drugAliasID,
MIN(trmin.dosage1) AS dosage1,
MIN(trmin.unit1) AS unit1,
MIN(trmax.dosage1) AS dosage2,
MIN(trmax.unit1) AS unit2
FROM
#tempResult tr
JOIN
#tempResult trmin ON trmin.RowID = tr.rowid AND trmin.drugAliasID = tr.drugAliasID
JOIN
#tempResult trmax ON trmax.RowID = tr.rowid AND trmax.drugAliasID = tr.drugAliasID
JOIN
(SELECT
MIN(RowID) AS rowid,
drugAliasID
FROM
#tempResult
GROUP BY
drugAliasID) tr1 ON tr1.rowid = trmin.RowID
JOIN
(SELECT
MAX(RowID) AS rowid,
drugAliasID
FROM
#tempResult
GROUP BY
drugAliasID) tr2 ON tr2.rowid = tr.RowID
GROUP BY
tr.drugAliasID
HAVING
count(tr.drugAliasID) > 1
Assuming your version of SQL Server supports the use of CTEs, you can simplify your query thus:
;with cte as
(select *, row_number() over (partition by drugaliasid order by rowid) rn
from #tempResult
)
select c.drugaliasid, c.dosage1, c.unit1, c2.dosage1 as dosage2, c2.unit1 as unit2
from cte c
left join cte c2 on c.drugaliasid = c2.drugaliasid and c.rn = 1 and c2.rn = 2
where c.rn = 1
Demo
This will give you the desired result, without having to use the pivot keyword.

Resources