How to Select Two tables without union and union all? - sql

Table1:
Id | Text | Parent Id | Number
**************************************
101 |robber | 201 | 1
102 |devel | 202 | 1
103 |programmer | 203 | 3
Table 2
Id | TO id | Parent Id | Number
**************************************
102 |355 | 201 | 1
104 |366 | 202 | 2
105 |377 | 203 | Null
I need to join two tables without using Union and union All
Out Put Like:
(Both table columns are same expect one To Id that columns add to last )
Id | Text | Parent Id | Number | To Id
101 |robber | 201 | 1 | Null
102 |devel | 202 | 2 | null
103 |programmer | 203 | 3 |Null
102 |Null | 201 | 1 |355
104 | Null | 202 | 2 | 366
105 |Null | 203 | null | 377

Try full join
select isnull(a.id,b.id) as id,
a.Text1,isnull(a.ParentId,b.ParentId) parentid,
isnull(a.Number,b.Number) numm,TOid
from #t a
full join #t1 b on a.Id=b.Id and a.ParentId=b.ParentId
data
declare #t table (Id int,Text1 varchar(50),ParentId int, Number int) insert into #t
(Id,Text1,ParentId, Number) values
(101 ,'robber' , 201 , 1),
(102 ,'devel' , 202 , 1),
(103 ,'programmer' , 203 , 3)
declare #t1 table (Id int,TOid int,ParentId int, Number int) insert into #t1
(Id,TOid,ParentId, Number) values
(102 ,355 , 201 , 1),
(104 ,366 , 202 , 2),
(105 ,377 , 203 , Null)

and for the non-union way you can use a temp table as follows
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
BEGIN
DROP TABLE #TempTable
END
CREATE TABLE #TempTable (
Id INT
,[Text] VARCHAR(20)
,ParentId INT
,Number INT
,ToId INT
)
INSERT INTO #TempTable (Id, [Text], ParentId, Number)
SELECT
Id
,[Text]
,ParentId
,Number
FROM
TableNameA
INSERT INTO #TempTable (Id, ToId, ParentId, Number)
SELECT
Id
,ToId
,ParentId
,Number
FROM
TableNameB
SELECT *
FROM
#TempTable
I would only use this way in circumstances that I definitely want a temp table of the results or if my logic has to be broken up for some reason, very rare for the later. There are still other ways yet but if you are not using a temp table union all should perform better than the other ways.

Related

SQL Server - SQL query to convert 0 or 1 or 2 rows into a single row with 2 columns

I have a schema as below
Test
--------------------
| Id | Name |
--------------------
| 1 | A001 |
| 2 | B001 |
| 3 | C001 |
--------------------
RelatedTest
---------------------------------
| Id | Name | TestId |
---------------------------------
| 1 | Jack | NULL |
| 2 | Joe | 2 |
| 3 | Jane | 3 |
| 4 | Julia | 3 |
---------------------------------
To briefly explain this schema RelatedTest has a nullable FK to Test and the FKId can appear either 0 or 1 or 2 times but never more than 2 times.
I am after a t-SQL query that reports the data in Test in the following format
TestReport
---------------------------------------------------------------------------
| TestId | TestName | RelatedTestName1 | RelatedTestName2 |
---------------------------------------------------------------------------
| 1 | A001 | NULL | NULL |
| 2 | B001 | Joe | NULL |
| 3 | C001 | Jane | Julia |
I can safely assume that TestReport will not need any more than two columns for RelatedTestName.
The schema is beyond my control and I am just looking to query it for some reporting.
I've been trying to utilise the Pivot function but I'm not entirely sure how I can use it so that RelatedTestName1 and RelatedTestName1 can be NULL in the case where there is no RelatedTest records. And also since RelatedTestName is a varchar I'm not sure how to apply an appropriate aggregate if that's what is needed.
Preparing Data:
DROP TABLE IF EXISTS Test
GO
CREATE TABLE Test (Id INT PRIMARY KEY, Name VARCHAR(10)) ON [PRIMARY]
GO
INSERT INTO Test Values
(1, 'A001')
,(2, 'B001')
,(3, 'C001')
GO
DROP TABLE IF EXISTS RelatedTest
GO
CREATE TABLE RelatedTest (
Id INT,
Name VARCHAR(10),
TestId INT FOREIGN KEY REFERENCES Test (Id)
) ON [PRIMARY]
GO
INSERT INTO RelatedTest Values
(1, 'Jack', NULL)
,(2, 'Joe', 2)
,(3, 'Jane', 3)
,(3, 'Julia', 3)
GO
Query:
;WITH CTE AS
(
SELECT TestId = T.Id
,TestName = T.Name
,RelatedTestName = RT.Name
,RN = ROW_NUMBER() OVER(PARTITION BY T.Id ORDER BY RT.Id ASC)
FROM Test T
LEFT JOIN RelatedTest RT
ON T.Id = RT.TestId
)
SELECT DISTINCT
C.TestId
,C.TestName
,RelatedTestName1 = (SELECT RelatedTestName FROM CTE A WHERE A.TestId = C.TestId AND A.RN = 1)
,RelatedTestName2 = (SELECT RelatedTestName FROM CTE A WHERE A.TestId = C.TestId AND A.RN = 2)
FROM CTE C;

Insert values from one table to another having different primary key

I have 2 tables. Tab A and Tab B
Tab A
Id Name
2 John
3 Peter
4 Rachel
I need to insert records in table B to get following:
Tab B
PrId ID Resident Date.
1 2 Yes 7/1/2018
2 3 Yes 7/1/2018
3 4 Yes 7/1/2018
PrId is the primary key of table B, Id comes from Table A and rest of the values are hard coded.
Please suggest the script to do the same
Are you looking to simply do a straight-forward insert from one table into another? If so, here's an example you can run in SSMS:
-- create table variables for illustration purposes --
DECLARE #tableA TABLE ( [Id] INT, [Name] VARCHAR(10) );
DECLARE #tableB TABLE ( [PrId] INT IDENTITY (1, 1), [Id] INT, [Resident] VARCHAR(10), [Date] SMALLDATETIME );
-- insert sample data into #tableA --
INSERT INTO #tableA ( [Id], [Name] ) VALUES ( 2, 'John' ), ( 3, 'Peter' ), ( 4, 'Rachel' );
-- show rows in #tableA --
SELECT * FROM #tableA;
/*
+----+--------+
| Id | Name |
+----+--------+
| 2 | John |
| 3 | Peter |
| 4 | Rachel |
+----+--------+
*/
-- insert records from #tableA to #tableB --
INSERT INTO #tableB (
[Id], [Resident], [Date]
)
SELECT
[Id], 'Yes', '07/01/2018'
FROM #tableA;
-- show inserted rows in #tableB --
SELECT * FROM #tableB;
/*
+------+----+----------+---------------------+
| PrId | Id | Resident | Date |
+------+----+----------+---------------------+
| 1 | 2 | Yes | 2018-07-01 00:00:00 |
| 2 | 3 | Yes | 2018-07-01 00:00:00 |
| 3 | 4 | Yes | 2018-07-01 00:00:00 |
+------+----+----------+---------------------+
*/
If you have your tables set up with a Primary Key and Foreign Key then you can run the following select query to join the two tables into one.
select a.PrId, b.ID, a.Resident, a.Date
from Table a inner join
Table b on a.PrID = b.ID
look up inner joins here https://www.w3schools.com/sql/sql_join_inner.asp
and foreign key https://www.w3schools.com/sql/sql_foreignkey.asp
In the future please do some research before posting

Get one row of grouped objects

I have a table that contains a Husband to Wife realtion.
The table contains two rows for each realtion(BTW,gender has no meaning.it could be Husband-Husband and Wife-Wife. just saying). meaning, the table might show result of two rows for a "connection":
Wife--Husband and\or Husband--Wife
The table looks like this:
Id1 | Id2 | ConnectiondID | RelatedConnectionId
-----------------------------------------------------
123 | 333 | FF45 | F421
333 | 123 | F421 | FF45
456 | 987 | F333 | F321
987 | 456 | F321 | F333
My expected result is to have only one relation per group:
Id1 | Id2
----------
123 | 333
456 | 987
This is actually very simple assuming you only want couples and your ID values are all unique and numeric, and does not require any self joins, functions or grouping:
declare #t table(Id1 int,Id2 int,ConnectiondID nvarchar(5),RelatedConnectionId nvarchar(5));
insert into #t values(123,333,'FF45','F421'),(333,123,'F421','FF45'),(456,444,'FF46','F422'),(444,456,'F422','FF46'),(789,555,'FF47','F423'),(555,789,'F423','FF47');
select *
from #t
where Id1 < Id2
order by Id1
Output:
+-----+-----+---------------+---------------------+
| Id1 | Id2 | ConnectiondID | RelatedConnectionId |
+-----+-----+---------------+---------------------+
| 123 | 333 | FF45 | F421 |
| 444 | 456 | F422 | FF46 |
| 555 | 789 | F423 | FF47 |
+-----+-----+---------------+---------------------+
If I am understanding your question correctly, you need to perform a self-join on the table e.g. ON t1.id1 = t2.id2 or ON t1.ConnectionId = t2.RelatedConnectionID and obviously this is joining both ways.
To limit this to just one way add a condition on the join predicate such that one of the values is less than or greater than the other; e.g.
DECLARE #tbl table( Id1 smallint PRIMARY KEY, Id2 smallint,ConnectiondID char(5),RelatedConnectionId char(5));
INSERT #tbl(Id1,Id2,ConnectiondID,RelatedConnectionId)
VALUES(123,333,'FF45','F421'),
(333,123,'F421','FF45'),
(456,222,'FF45','F421'),
(222,456,'F421','FF45'),
(789,111,'FF45','F421'),
(111,789,'F421','FF45');
SELECT *
FROM #tbl t1
JOIN #tbl t2 ON t2.Id1 = t1.Id2 AND t2.Id1 > t1.Id1;
For example
DECLARE #T TABLE (id1 int, id2 int,ConnectiondID varchar(5),RelatedConnectionId varchar(5) )
INSERT INTO #T (Id1,Id2,ConnectiondID,RelatedConnectionId)
VALUES
(123 , 333 ,'FF45','F421'),
(333 , 123 , 'F421','FF45'),
(2123 , 2333 ,'2FF45','2F421'),
(2333 , 2123 , '2F421','2FF45'),
(3 , 2 , 'AAAA','BBB'),
(2 , 3 , 'BBB','AAAA')
SELECT
a.*
FROM
#t a
WHERE
CASE
WHEN ConnectiondID > RelatedConnectionId
THEN RelatedConnectionId
ELSE NULL
END IS NULL

Querying data groups with total row before starting next group?

I need to query some data in the below format in SQL Server:
Id Group Price
1 A 10
2 A 20
Sum 30
1 B 6
2 B 4
Sum 10
1 C 100
2 C 200
Sum 300
I was thinking to do it in the follwoing steps:
Query one group
In other query do sum
Use Union operator to combine this result set
Do step 1-3 for all groups and finally return all sub sets of data using union.
Is there a better way to do this ? May be using some out of box feature ? Please advise.
Edit:
As per suggestions and code sample I tried this code:
Select
Case
when id is null then 'SUM'
else CAST(id as Varchar(10)) end as ID,
Case when [group] is null then 'ALL' else CAST([group] as Varchar(50)) end as [group]
,Price from
(
SELECT Id, [Group],BGAApplicationID,Section, SUM(PrimaryTotalArea) AS price
FROM vwFacilityDetails
where bgaapplicationid=1102
GROUP BY Id, [Group],BGAApplicationID,Section WITH ROLLUP
) a
And Even this code as well:
Select Id, [Group],BGAApplicationID,Section, SUM(PrimaryTotalArea) AS price
From vwFacilityDetails
Where Not ([group] Is Null And id Is Null And BGAApplicationId is null and section is null) and BGAApplicationId=1102
Group By Id, [Group],BGAApplicationID,Section
With Rollup
In results it groups up the data but for every record it shows it 3 times (in both above codes) like:
2879 Existing Facilities Whole School 25.00
2879 Existing Facilities Whole School 25.00
2879 Existing Facilities Whole School 25.00
2879 ALL 25.00
I guess there is some issue in my query, please guide me here as well.
Thanks
SQL Server introduced GROUPING SETS which is what you should be looking to use.
SQL Fiddle
MS SQL Server 2008 Schema Setup:
Create Table vwFacilityDetails (
id int not null,
[group] char(1) not null,
PrimaryTotalArea int not null,
Section int,
bgaapplicationid int
);
Insert Into vwFacilityDetails (id, [group], Section,bgaapplicationid,PrimaryTotalArea) values
(1, 'A', 1,1102,2),
(1, 'A', 1,1102,1),
(1, 'A', 1,1102,7),
(2, 'A', 1,1102,20),
(1, 'B', 1,1102,6),
(2, 'B', 1,1102,4),
(1, 'C', 1,1102,100),
(2, 'C', 1,1102,200);
Query 1:
SELECT CASE WHEN Id is null then 'SUM'
ELSE Right(Id,10) end Id,
[Group],BGAApplicationID,Section,
SUM(PrimaryTotalArea) price
FROM vwFacilityDetails
where bgaapplicationid=1102
GROUP BY GROUPING SETS (
(Id,[Group],BGAApplicationID,Section),
([Group])
)
ORDER BY [GROUP],
ID;
Results:
| ID | GROUP | BGAAPPLICATIONID | SECTION | PRICE |
----------------------------------------------------
| 1 | A | 1102 | 1 | 10 |
| 2 | A | 1102 | 1 | 20 |
| SUM | A | (null) | (null) | 30 |
| 1 | B | 1102 | 1 | 6 |
| 2 | B | 1102 | 1 | 4 |
| SUM | B | (null) | (null) | 10 |
| 1 | C | 1102 | 1 | 100 |
| 2 | C | 1102 | 1 | 200 |
| SUM | C | (null) | (null) | 300 |
Select
id,
[Group],
SUM(price) AS price
From
Test
Group By
[group],
id
With
Rollup
http://sqlfiddle.com/#!3/080cd/8
Select Case when id is null then 'SUM' else CAST(id as Varchar(10)) end as ID
,Case when [group] is null then 'ALL' else CAST([group] as Varchar(10)) end as [group]
,Price from
(
SELECT id, [group], SUM(price) AS Price
FROM IG
GROUP BY [GROUP],ID WITH ROLLUP
) a

SELECT inherit values from parent in a hierarchy

I'm trying to acheive through T-SQL (in a stored procedure) a way to copy a value from a parent into the child when retrieving rows. Here is some example data:
DROP TABLE TEST_LEVELS
CREATE TABLE TEST_LEVELS(
ID INT NOT NULL
,VALUE INT NULL
,PARENT_ID INT NULL
,LEVEL_NO INT NOT NULL
)
INSERT INTO TEST_LEVELS (ID, VALUE, PARENT_ID, LEVEL_NO) VALUES (1, 10000, NULL, 1)
INSERT INTO TEST_LEVELS (ID, VALUE, PARENT_ID, LEVEL_NO) VALUES (2, NULL, 1, 2)
INSERT INTO TEST_LEVELS (ID, VALUE, PARENT_ID, LEVEL_NO) VALUES (3, NULL, 2, 3)
INSERT INTO TEST_LEVELS (ID, VALUE, PARENT_ID, LEVEL_NO) VALUES (4, 20000, NULL, 1)
INSERT INTO TEST_LEVELS (ID, VALUE, PARENT_ID, LEVEL_NO) VALUES (5, NULL, 4, 2)
INSERT INTO TEST_LEVELS (ID, VALUE, PARENT_ID, LEVEL_NO) VALUES (6, 25000, 5, 3)
INSERT INTO TEST_LEVELS (ID, VALUE, PARENT_ID, LEVEL_NO) VALUES (7, NULL, 6, 4)
Selecting the data as follows:
SELECT ID, VALUE, LEVEL_NO
FROM TEST_LEVELS
results in:
+----+-------+----------+
| ID | VALUE | LEVEL_NO |
+----+-------+----------+
| 1 | 10000 | 1 |
| 2 | NULL | 2 |
| 3 | NULL | 3 |
| 4 | 20000 | 1 |
| 5 | NULL | 2 |
| 6 | 25000 | 3 |
| 7 | NULL | 4 |
+----+-------+----------+
But I need something like this (values are inherited by the parent):
+----+-------+----------+
| ID | VALUE | LEVEL_NO |
+----+-------+----------+
| 1 | 10000 | 1 |
| 2 | 10000 | 2 |
| 3 | 10000 | 3 |
| 4 | 20000 | 1 |
| 5 | 20000 | 2 |
| 6 | 25000 | 3 |
| 7 | 25000 | 4 |
+----+-------+----------+
Can this be achieved without using cursors (it must also run on SQL Server 2005)?
Use:
;with cte
as
(
select t.ID, t.VALUE, t.PARENT_ID, t.LEVEL_NO
from #t t
where t.Value is not null
union all
select t.ID, c.Value, t.PARENT_ID, t.LEVEL_NO
from cte c
join #t t on t.PARENT_ID = c.ID
where t.Value is null
)
select c.ID, c.Value, c.LEVEL_NO
from cte c
order by c.ID
Output:
ID Value LEVEL_NO
----------- ----------- -----------
1 10000 1
2 10000 2
3 10000 3
4 20000 1
5 20000 2
6 25000 3
7 25000 4
Maybe something like this:
;WITH cte_name(ID,VALUE,PARENT_ID,LEVEL_NO)
AS
(
SELECT
tbl.ID,
tbl.VALUE,
tbl.PARENT_ID,
tbl.LEVEL_NO
FROM
TEST_LEVELS AS tbl
WHERE
tbl.PARENT_ID IS NULL
UNION ALL
SELECT
tbl.ID,
ISNULL(tbl.VALUE,cte_name.VALUE),
tbl.PARENT_ID,
tbl.LEVEL_NO
FROM
cte_name
JOIN TEST_LEVELS AS tbl
ON cte_name.ID=tbl.PARENT_ID
)
SELECT
*
FROM
cte_name
ORDER BY
ID
One way to do it:
SELECT T.ID,
case when T.VALUE IS NULL
THEN (SELECT A.VALUE FROM TEST_LEVELS A WHERE A.ID = T.PARENT_ID)
ELSE T.VALUE
END,
T.LEVEL_NO
FROM TEST_LEVELS T