SQL Server : nonstandard query - sql-server

I have a table dzialki_wlasciciele
id_dzialki | id_wlasc | id_malz |
1 | 1 | 2
1 | 2 | 1
2 | 1 | 2
3 | 1 | 2
Now I need two queries - one to return two rows where id_dzialki = 1 (where it has two id_wlasc where id_wlasc of second row = id_malz of first row)
And second query should return id_dzialki = 2 and = 3 (where there is no second record where id_wlasc = id_malz)
Second question I have :
select *
from dzialki_wlasciciele dw1
where dw1.ID_WLASC = 1
and dw1.id_dzialki not in (select dw2.id_dzialki
from dzialki_wlasciciele dw2
where ID_malz = 1)
But how about first question ?

If I understand correctly:
DECLARE #dzialki_wlasciciele TABLE
(
id_dzialki INT ,
id_wlasc INT ,
id_malz INT
)
INSERT INTO #dzialki_wlasciciele
VALUES ( 1, 1, 2 ),
( 1, 2, 1 ),
( 2, 1, 2 ),
( 3, 1, 2 )
SELECT d1.*
FROM #dzialki_wlasciciele d1
JOIN #dzialki_wlasciciele d2 ON d2.id_dzialki = d1.id_dzialki
AND d2.id_wlasc = d1.id_malz
WHERE d1.id_dzialki = 1
Output:
id_dzialki id_wlasc id_malz
1 1 2
1 2 1

Related

Sum two columns in SQL and optimise SQL query

I have the following query which returns two columns, I want to sum both columns and create the third column through summing the two.
Is there any way I can recreate the below query by removing the subquery? Any way I can achieve the same through joins?
SELECT
IIF(c2.isdeleted = 1 OR c2.approved = 0, 0, 1) AS Contentcount,
(SELECT COUNT(c1.content)
FROM comments c1
WHERE c1.parentcommentid = c2.id
AND c1.isdeleted = 0
AND c1.approved = 1) ChildContentcount --Anyway to remove the subquery
FROM
comments c2
WHERE
c2.discussionid = '257943'
AND c2.parentcommentid IS NULL
ORDER BY
c2.pinned DESC,
c2.createddate
Sample data:
+----------+--------------+
| content | childcontent |
+----------+--------------+
| 1 | 8 |
| 0 | 0 |
| 1 | 3 |
+----------+--------------+
Expected output:
+----------+----------------+---------+
| content | childcontent | sumdata |
+----------+----------------+---------+
| 1 | 8 | 9 |
| 0 | 0 | 0 |
| 1 | 3 | 4 |
| 1 | 8 | 9 |
+----------+----------------+---------+
You can use CROSS APPLY or OUTER APPLY instead of a correlated subquery.
Then you can re-use the values.
select c.pinned, c.createddate
, c.discussionid
, ca1.content
, ca2.childcontent
, (ca1.content + ca2.childcontent) AS sumdata
FROM comments c
CROSS APPLY
(
SELECT CASE
WHEN c.isdeleted = 1 OR c.approved = 0 THEN 0
ELSE 1
END AS content
) ca1
CROSS APPLY
(
SELECT COUNT(c2.content) AS childcontent
FROM comments c2
WHERE c2.parentcommentid = c.id
AND c2.isdeleted = 0
AND c2.approved = 1
) ca2
WHERE c.discussionid = '257943'
AND c.parentcommentid IS NULL
ORDER BY
c.pinned DESC,
c.createddate;
Subquery and sum the columns :
select tbl.* , Contentcount+ChildContentcount third_sum from
(
select IIF(c2.isdeleted = 1 OR c2.approved = 0, 0, 1) AS Contentcount,
(SELECT COUNT(c1.content)
FROM comments c1
WHERE c1.parentcommentid = c2.id
AND c1.isdeleted = 0
AND c1.approved = 1) ChildContentcount
FROM
comments c2
WHERE
c2.discussionid = '257943'
AND c2.parentcommentid IS NULL ) tbl
If you supply sql fiddle, we can try to create it alternative ways

How to update column of a table from another table in sequence when table don't relate

I am not sure how to update column's value from another table in SQL Server when table don't relate to each other by unique key.
A
+--------+--------+--------+
| Id | col2_A | col3_A |
+--------+--------+--------+
| 1 | 3 | 5 |
| 2 | 3 | 3 |
| 3 | 3 | 2 |
| 4 | 3 | 1 |
| 5 | 3 | 8 |
+--------+--------+--------+
B
+--------+--------+
| Id | Col1_B |
+--------+--------+
| 11 | 6 |
| 12 | 7 |
| 13 | 8 |
| 14 | 9 |
| 15 | 10 |
+--------+--------+
Required Result:
+--------+--------+--------+
| Id | col2_A | col3_A |
+--------+--------+--------+
| 1 | 1 | 6 |
| 2 | 1 | 7 |
| 3 | 1 | 8 |
| 4 | 1 | 9 |
| 5 | 1 | 10 |
+--------+--------+--------+
Pseudo code
Replace/update Col3_A with col1_B in sequence.
My code: doesn't work as my code updates Col3_A with random values
Update A
Set col2_A = '1', col3_A = (select col1_B from B)
Do I need to use cursor?Please help
Try this:
DECLARE #t1 TABLE ( id INT, col1 INT, col2 INT );
DECLARE #t2 TABLE ( id INT, col1 INT );
INSERT INTO #t1
VALUES ( 1, 3, 5 ),
( 2, 3, 3 ),
( 3, 3, 2 ),
( 4, 3, 1 ),
( 5, 3, 8 );
INSERT INTO #t2
VALUES ( 11, 6 ),
( 12, 7 ),
( 13, 8 ),
( 14, 9 ),
( 15, 10 );
UPDATE l
SET l.col1 = '1', l.col2 = r.col1
FROM ( SELECT ROW_NUMBER() OVER ( ORDER BY id ) row ,
*
FROM #t1
) AS l
INNER JOIN ( SELECT ROW_NUMBER() OVER ( ORDER BY id ) row ,
*
FROM #t2
) AS r ON r.row = l.row
WHERE r.row = l.row;
SELECT *
FROM #t1;
Result:
Is this what you want?
update A, B set col2_A = 1, A.col3_A = B.Col1_B where A.Id = B.Id;
Edit 1
OK, then add pseudo id, and drop it after update.
alter table A add column id1 int;
set #n = 0;
update A set id1 = #n := #n+1;
update A, (select #n := #n + 1 id, col1_B from B, (SELECT #n := 0) m) b set A.col3_A = b.col1_B where A.id1 = b.id;
alter table A drop column id1;

Recursive CTE to update parent records through multiple levels

Will a CTE use data that is updated as part of the CTE in the next recursion? I am trying to attempt this CTE because the performance of a similar UPDATE logic inside of a WHILE loop is not performing well and I was hoping that using the CTE would be more set based and perform better.
I am having trouble with a recursive CTE updating a table until the parent rows are all marked properly.
SQL Fiddle
The SQL fiddle shows the table and basic CTE. Before even adding in any of the AND/OR or level logic, I cannot seem to get the CTE to climb the hierarchy and mark the parents as "met".
Here is the example table:
| LogicID | ParentLogic | Depth | Type | Description | Met |
|--------- |------------- |------- |------ |------------------------------------- |----- |
| 1 | NULL | NULL | NULL | Conditions All Met | 0 |
| 2 | 1 | 1 | AND | The sky or ocean is blue | 0 |
| 3 | 2 | 2 | OR | The sky is blue | 0 |
| 4 | 2 | 2 | OR | The ocean is blue | 1 |
| 5 | 1 | 1 | AND | The grass is green or road is black | 0 |
| 6 | 5 | 2 | OR | The grass is green | 1 |
| 7 | 5 | 2 | OR | The road is black | 0 |
| 8 | 1 | 1 | AND | Birds, bugs or the 4 below | 0 |
| 9 | 8 | 2 | OR | There are birds | 0 |
| 10 | 8 | 2 | OR | There are bugs | 0 |
| 11 | 8 | 2 | OR | All 4 below | 0 |
| 12 | 11 | 3 | AND | There are dogs | 1 |
| 13 | 11 | 3 | AND | There are cats | 1 |
| 14 | 11 | 3 | AND | There are people | 1 |
| 15 | 11 | 3 | AND | There are chairs | 1 |
DROP TABLE MyLogic
CREATE TABLE MyLogic
(
LogicID int
,ParentLogic int
,Depth int
,Type varchar(4)
,Description varchar(35)
,Met int
);
INSERT INTO MyLogic
( LogicID, ParentLogic, Depth, Type, Description, Met )
VALUES
( 1, NULL, NULL, NULL, 'Conditions All Met', 0 ),
( 2, 1, 1, 'AND', 'The sky or ocean is blue', 0 ),
( 3, 2, 2, 'OR', 'The sky is blue', 0 ),
( 4, 2, 2, 'OR', 'The ocean is blue', 1 ),
( 5, 1, 1, 'AND', 'The grass is green or road is black', 0 ),
( 6, 5, 2, 'OR', 'The grass is green', 1 ),
( 7, 5, 2, 'OR', 'The road is black', 0 ),
( 8, 1, 1, 'AND', 'Birds, bugs or the 4 below', 0 ),
( 9, 8, 2, 'OR', 'There are birds', 0 ),
( 10, 8, 2, 'OR', 'There are bugs', 0 ),
( 11, 8, 2, 'OR', 'All 4 below', 0 ),
( 12, 11, 3, 'AND', 'There are dogs', 1 ),
( 13, 11, 3, 'AND', 'There are cats', 1 ),
( 14, 11, 3, 'AND', 'There are people', 1 ),
( 15, 11, 3, 'AND', 'There are chairs', 1 )
This is just a sample of a much more complicated set of logic. Basically the idea is that I need each set of children to "rollup" to the parent using the logic in the table. The depth is variable but is likely to be 7 deep.
So, LogicID 12,13,14,15 are ANDed together and would then mark 11 as Met. Then 9,10,11 would be evaluated and if any (OR) then mark 8 as Met. And so on, until the top level parent LogicID 1 is either Met or not Met.
Can this be done with the CTE and if so can someone help me get it going?
EDIT::
Thanks for the help - as requested here is the update statement.
DECLARE #maxdepth AS int = ( SELECT MAX (Depth) FROM MyLogic)
DECLARE #counter AS int = 0
WHILE ( #counter < #maxdepth )
BEGIN
UPDATE
UP
SET
UP.Met =
--SELECT *,
CASE
WHEN ORIG.Type = 'AND' AND ORIG.Met = 0 AND COUNTS.CountMet = 2 THEN 0
WHEN ORIG.Type = 'AND' AND ORIG.Met = 0 AND COUNTS.CountMet = 1 THEN 0
WHEN ORIG.Type = 'AND' AND ORIG.Met = 1 AND COUNTS.CountMet = 2 THEN 0
WHEN ORIG.Type = 'AND' AND ORIG.Met = 1 AND COUNTS.CountMet = 1 THEN 1
WHEN ORIG.Type = 'OR' AND ORIG.Met = 1 AND COUNTS.CountMet = 1 THEN 1
WHEN ORIG.Type = 'OR' AND ORIG.Met = 0 AND COUNTS.CountMet = 2 THEN 1
WHEN ORIG.Type = 'OR' AND ORIG.Met = 1 AND COUNTS.CountMet = 2 THEN 1
WHEN ORIG.Type = 'OR' AND ORIG.Met = 0 AND COUNTS.CountMet = 1 THEN 0
END
FROM
MyLogic UP
INNER JOIN dbo.MyLogic ORIG
ON UP.LogicID = ORIG.ParentLogic
INNER JOIN ( SELECT
DIST.ParentLogic
,COUNT(DISTINCT DIST.Met) AS CountMet
FROM
MyLogic DIST
GROUP BY
DIST.ParentLogic
) COUNTS
ON ORIG.ParentLogic = COUNTS.ParentLogic
SET #counter = #counter + 1
END
I do not believe you will be able to accomplish your goal in this scenario with CTE. Every approach I tried with CTE hinges on being able to use GROUP BY in the recursive part of the CTE which is not allowed.
Here is an alternative that should speed up your UPDATE. It's still a bit iterative, but it seems to be a good bit faster in my quick testing owing mostly to more set-based approach and fewer joins needed. It should scale more efficiently as well than the current process.
DECLARE #D AS INT = ( SELECT MAX (Depth) FROM MyLogic)
WHILE #D > 0 BEGIN
UPDATE P SET
Met = C.Met
FROM MyLogic P
INNER JOIN (
SELECT
ParentLogic,
CASE
WHEN SUM(CASE WHEN Type = 'OR' THEN Met ELSE 0 END) > 0
OR SUM(CASE WHEN Type = 'AND' THEN Met ELSE 0 END) = COUNT(*)
THEN 1 ELSE 0 END AS Met
FROM MyLogic
WHERE Depth = #D
GROUP BY
ParentLogic
) C -- Only update parents with children
ON P.LogicID = C.ParentLogic
WHERE COALESCE(P.Depth, 0) = #D - 1 -- Get next level up
SET #D = #D - 1
END
SELECT * FROM MyLogic

Order parent child records by parent group and children

I need sort query results by specific two related columns. My table is:
Row no | Col 1 | Col 2 | Col 3 | Col 4
1 | 1 | X | 1 | 5
2 | 2 | Y | 1 | 6
3 | 5 | Z | 2 | 7
4 | 6 | T | 2 | 0
5 | 7 | T | 3 | 0
6 | 6 | W | 2 | 0
The values in Col 4 represents the child record linked to Col 1.
So for Row no = 1 the next child record is row 3, where Col 1 holds the value of Col 4 from the first row.
The next child row for row 3 is row 5, based on the link between Col 1 and Col 4.
And I'd like to return this results:
Row no | Col 1 | Col 2 | Col 3 | Col 4
1 | 1 | X | 1 | 5
3 | 5 | Z | 2 | 7
5 | 7 | T | 3 | 0
2 | 2 | Y | 1 | 6
4 | 6 | T | 2 | 0
6 | 6 | W | 2 | 0
So I want the ordering to show a Parent row, followed by it's child rows, before moving on to the next top level Parent row.
You can achieve what you're after with a Recursive CTE to find all the parent records and link them to their child records.
Dummy table setup:
CREATE TABLE #Table1
(
[Row no] INT ,
[Col 1] INT ,
[Col 2] VARCHAR(1) ,
[Col 3] INT ,
[Col 4] INT
);
INSERT INTO #Table1
( [Row no], [Col 1], [Col 2], [Col 3], [Col 4] )
VALUES ( 1, 1, 'X', 1, 5 ),
( 2, 2, 'Y', 1, 6 ),
( 3, 5, 'Z', 2, 7 ),
( 4, 6, 'T', 2, 0 ),
( 5, 7, 'T', 3, 0 ),
( 6, 6, 'W', 2, 0 );
Recursive CTE:
;WITH cte
AS ( SELECT * ,
ROW_NUMBER() OVER ( ORDER BY t1.[Col 1] ) GroupNo
FROM #Table1 t1
WHERE t1.[Col 1] NOT IN ( SELECT [Col 4] FROM #Table1 )
UNION ALL
SELECT t.* ,
cte.GroupNo
FROM #Table1 t
INNER JOIN cte ON cte.[Col 4] = t.[Col 1]
)
SELECT *
FROM cte
ORDER BY cte.GroupNo , cte.[Row no]
DROP TABLE #Table1
This combines 2 queries with a UNION ALL. The first query finds the top level items where the value of [Col 1] does not appear in [Col 4]:
WHERE t1.[Col 1] NOT IN ( SELECT [Col 4] FROM #Table1 )
The second query finds the child records on the first query with this JOIN:
INNER JOIN cte ON cte.[Col 4] = t.[Col 1]
For the ordering, I've used the following to give the the results of the first query a GroupNo, which is used later to order the records:
ROW_NUMBER() OVER ( ORDER BY t1.[Col 1] ) GroupNo

Sorting columns to be multi-row

I have data in SQL Server like this:
floor | Apartment
1 1
1 2
1 3
2 4
2 5
2 6
because one floor has 3 apartments, I want to sort or convert the Apartment column to be a row like the flowing
4 | 5 | 6
1 | 2 | 3
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table YourTable
(
Floor int,
Apartment int
)
go
insert into YourTable values
( 1, 1),
( 1, 2),
( 1, 3),
( 2, 4),
( 2, 5),
( 2, 6)
Query 1:
select P.Floor,
P.[1] as Room1,
P.[2] as Room2,
P.[3] as Room3
from (
select Floor,
Apartment,
row_number() over(partition by Floor order by Apartment) as rn
from YourTable
) as T
pivot(min(T.Apartment) for T.rn in ([1], [2], [3])) as P
Results:
| FLOOR | ROOM1 | ROOM2 | ROOM3 |
|-------|-------|-------|-------|
| 1 | 1 | 2 | 3 |
| 2 | 4 | 5 | 6 |

Resources