SELECT inherit values from Parent (self-references) - sql-server

I have 02 tables Rubrique and BulletinRubrique
the table Rubrique contain the following columns :
ID int not null,
Name, varchar(max) not null,
RubriqueA_ID int null,
RubriqueB_ID int null
with data for example :
+-------+---------+--------------+--------------+
| ID | Name | RubriqueA_ID | RubriqueB_ID |
+-------+---------+--------------+--------------+
| 1 | R1 | 2 | 3 |
| 2 | R2 | 1 | 2 |
| 3 | R3 | NULL | NULL |
| 4 | R4 | NULL | 6 |
| 5 | R5 | 6 | NULL |
| 6 | R6 | NULL | 1 |
+-------+---------+--------------+--------------+
the two columns RubriqueA_ID, RubriqueB_ID are the foreigns Keys for the same table Rubrique (self-referencing) and they might be NULL
For the table BulletinRubrique :
ID int not null,
EmployeID int not null,
RubriqueID int not null,
Value float not null
with data :
+-------+-----------+--------------+------------+
| ID | EmployeID | Rubrique_ID | Value |
+-------+-----------+--------------+------------+
| B1 | EMP1 | 1 | 150 |
| B1 | EMP1 | 2 | 220 |
| B1 | EMP1 | 3 | 195 |
| B1 | EMP1 | 4 | 170 |
| B1 | EMP1 | 5 | 320 |
| B1 | EMP1 | 6 | 745 |
+-------+-----------+--------------+------------+
What I am trying to do is bulding the sql query to get result as :
+-------+-----------+--------------+------------+----------+---------+
| ID | EmployeID | Rubrique_ID | Value | A_Value | B_Value |
+-------+-----------+--------------+------------+----------+---------+
| B1 | EMP1 | 1 | 150 | 220 | 195 |
| B1 | EMP1 | 2 | 220 | 150 | 220 |
| B1 | EMP1 | 3 | 195 | NULL | NULL |
| B1 | EMP1 | 4 | 170 | NULL | 745 |
| B1 | EMP1 | 5 | 320 | 745 | NULL |
| B1 | EMP1 | 6 | 745 | NULL | 150 |
+-------+-----------+--------------+------------+----------+---------+
Please help me to build this query and thanks

http://rextester.com/FIJE42564 is the working code
SELECT t2.ID, t2.EmployeID, t2.RubriqueID, t2.Value, t2.A_Value, r2.Value AS B_value FROM BulletinRubrique r2
RIGHT JOIN
(
SELECT t1.ID, t1.EmployeID, t1.RubriqueID, t1.Value, r1.VALUE AS A_VALUE, t1.B_VALUE FROM BulletinRubrique r1
RIGHT JOIN (
SELECT b.ID, b.EmployeID,b.RubriqueID, b.Value, r.RubriqueA_ID AS A_Value, r.RubriqueB_ID AS B_Value
FROM BulletinRubrique b RIGHT JOIN Rubrique r ON r.ID = b.RubriqueID ) t1
ON t1.A_Value = r1.RubriqueID
)t2
ON t2.B_Value = r2.RubriqueID
ORDER BY t2.RubriqueID

Being a fan of nested CTE, this is the way I tried solving this
WITH CTE1 as(
SELECT
BR.Id, BR.EmployeID, BR.RubriqueID, BR.value, R1.Rubriquea_Id, R2.Rubriqueb_Id
FROM
BulletinRubrique BR
LEFT JOIN
Rubrique R1 ON R1.Id = BR.RubriqueID
LEFT JOIN
Rubrique R2 ON R2.Id = BR.RubriqueID
),
CTE2 as (
SELECT
C1.Id, C1.EmployeID, C1.RubriqueID, C1.value, C2.value as A_Value, C3.value as B_Value
FROM
CTE1 C1
LEFT JOIN
CTE1 C2 ON C1.Rubriquea_Id = C2.RubriqueID
LEFT JOIN
CTE1 C3 ON C1.RubriqueB_Id = C3.RubriqueID
)
SELECT C1.Id,
C1.EmployeID,
C1.RubriqueID,
C1.value,
C1.A_Value as A_Value,
C1.B_Value as B_Value FROM CTE2 C1
ORDER BY Id

Related

Results of join listed in rows vs additional columns?

I have 2 tables, with the same exact fields and fields names. i am trying to inner join them but im having some difficulty determining how i can get my results in my desired format.
I know i can do select a.customer, a.id, a.date, a.line, a.product, b.customer, b.id, b.date, b.line, b.product but instead of having my A data and B data on the same row, id like for them to be on seperate rows.
I have 2 tables, with the same exact fields and fields names, i am trying to inner join them so that unique line becomes a row.
Table A:
|customer| id | Date | line | Product|
|--------|-----|---------|------|--------|
| 445678 | 123 | 1/1/22 | 10 | 88975 |
| 853652 | 456 | 1/10/22 | 5 | 55876 |
| 845689 | 789 | 1/25/22 | 1 | 45587 |
TABLE B:
|customer| id | Date | line | Product|
|--------|-----|---------|------|--------|
| 445678 | 489 | 1/1/22 | 1 | 87574 |
| 853652 | 853 | 1/10/22 | 12 | 45678 |
| 587435 | 157 | 2/12/22 | 3 | 25896 |
DESIRED RESULTS:
|customer| id | Date | line | Product|
|--------|-----|---------|------|--------|
| 445678 | 123 | 1/1/22 | 10 | 88975 |
| 445678 | 489 | 1/1/22 | 1 | 87574 |
| 853652 | 456 | 1/10/22 | 5 | 55876 |
| 853652 | 853 | 1/10/22 | 12 | 45678 |
my query:
select a.customer, a.id, a.date, a.line, a.product
from data1 a
inner join data2 b
on a.date = b.date
and a.customer = b.customer

How to get only one data from table if value is same in 2 columns in SQL Server?

I have three tables as below
Table 1 - DevInfo
+----------+--------+-----------+-------------+------+
| Center | DevId | DevType |LatestDate | DEL |
+----------+--------+-----------+-------------+------+
| C1 | 111 | T1 | 01/06/2020 | 0 |
| C1 | 222 | T2 | 01/06/2020 | 0 |
| C2 | 111 | T3 | 01/06/2020 | 0 |
| C2 | 333 | T4 | 01/06/2020 | 0 |
| C3 | 222 | T5 | 03/06/2020 | 0 |
| C4 | 444 | T6 | 01/06/2020 | 0 |
+----------+--------+-----------+-------------+------+
Table 2 - CenInfo
+----------+-------------+
| Center |LatestDate |
+----------+-------------+
| C1 | 01/06/2020 |
| C1 | 01/06/2020 |
| C2 | 01/06/2020 |
| C2 | 01/06/2020 |
| C3 | 03/06/2020 |
| C4 | 01/06/2020 |
+----------+-------------+
Table 3 - TypeInfo
+-----------+-------------+
| DevType |LatestDate |
+-----------+-------------+
| T1 | 01/06/2020 |
| T2 | 01/06/2020 |
| T3 | 01/06/2020 |
| T4 | 01/06/2020 |
| T5 | 03/06/2020 |
| T6 | 01/06/2020 |
+-----------+-------------+
I want to get data from DevInfo table, where
DevInfo table's center is same as in CenInfo table and DevInfo table's Dev Type is same as in TypeInfo table.
If DevId is same(e.g 111) for records then skip the record with DevType = "T3"
If DevId is same for records and DevType is not "T3" then select record with latest "LatestDate" value.
I want output like this:
+----------+--------+-----------+-------------+
| Center | Dev id | Dev Type |Latest Date |
+----------+--------+-----------+-------------+
| C1 | 111 | T1 | 01/06/2020 |
| C2 | 333 | T4 | 01/06/2020 |
| C3 | 222 | T5 | 03/06/2020 |
| C4 | 444 | T6 | 01/06/2020 |
+----------+--------+-----------+-------------+
I get the answer of 1st using an Inner Join,
Query as below :
Select
Center, DevId, DevType, LatestDate
From DevInfo DI
INNER JOIN CenInfo CI ON CI.Center = DI.Center
INNER JOIN TypeInfo TI ON TI.DevType = DI.DevType
WHERE DI.DEL = '0'
but didn't get any solution for 2 and 3
Please help me with that.
Thank you in advance.
You can use windowed ROW_NUMBER function:
WITH DevInfoFilteredAndSorted AS (
SELECT
DI.Center,
DI.DevId,
DI.DevType,
DI.LatestDate,
ROW_NUMBER() OVER (PARTITION BY DI.DevId ORDER BY CASE WHEN DI.DevType = 'T3' THEN 1 ELSE 0 END, DI.LatestDate DESC) AS RN
FROM DevInfo AS DI
INNER JOIN CenInfo AS CI
ON DI.Center = CI.Center
INNER JOIN TypeInfo AS TI
ON DI.DevType = TI.DevType
WHERE DI.DEL = 0
)
SELECT DI.Center, DI.DevId AS "Dev id", DI.DevType AS "Dev Type", DI.LatestDate AS "Latest Date"
FROM DevInfoFilteredAndSorted AS DI
WHERE DI.RN = 1
Example on dbfiddle.uk
Use CTE to get RowNumber as per your desired criteria and then perform join like below.
WITH DI AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY DevId ORDER BY IIF(DevType = 'T3', 1, 0), LatestDate DESC) AS RowNumber
FROM DevInfo
)
SELECT DI.Center, DI.DevId, DI.DevType, DI.LatestDate
From DI
INNER JOIN CenInfo CI ON CI.Center = DI.Center
INNER JOIN TypeInfo TI ON TI.DevType = DI.DevType
WHERE DI.RowNumber = 1

Divide selected value by count(*)

I have a Microsoft SQL Server with the following tables:
Projects
BookedHours (with fk_Project = Projects.ID)
Products
ProjectsToProducts (n:m with fk_Projects = Projects.ID and fk_Products = Products.ID)
I now want to select how many hours are booked to which product per month. The problem is, that one project can have multiple products (that's why I need the n:m table).
If I do the following, it will count the hours twice if a project has two products.
SELECT
P.ID AS fk_Product, MONTH(B.Datum) AS Monat, SUM(B.Hours) AS Stunden
FROM
tbl_BookedHours AS B
INNER JOIN
tbl_Projects AS M on B.fk_Project = M.ID
INNER JOIN
tbl_ProjectProduct AS PP ON PP.fk_Project = M.ID
INNER JOIN
tbl_Products AS P ON PP.fk_Product = P.ID
WHERE
YEAR(B.Datum) = 2020
GROUP BY
P.ID, MONTH(B.Datum)
ORDER BY
P.ID, MONTH(B.Datum)
I can get the number of products for each project with this SQL:
SELECT fk_Project, COUNT(*) AS Cnt
FROM tbl_ProjectProduct
GROUP By fk_MainProject
But how can I now divide the hours for each project by its individual factor and add it all up per product and month?
I could do it in my C# program or I could use a cursor and iterate through all projects, but I think there should be an more elegant way.
Edit with sample data:
|----------------| |----------------| |------------------------------|
| tbl_Projects | | tbl_Products | | tbl_ProjectProduct |
|----------------| |----------------| |------------------------------|
| ID | Name | | ID | Name | | ID | fk_Project | fk_Product |
|----+-----------| |----+-----------| |------------------------------|
| 1 | Project 1 | | 1 | Product 1 | | 1 | 1 | 1 |
| 2 | Project 2 | | 2 | Product 2 | | 2 | 1 | 2 |
| 3 | Project 3 | | 3 | Product 3 | | 3 | 2 | 1 |
| 4 | Project 4 | | 4 | Product 4 | | 4 | 3 | 3 |
|----------------| |----------------| | 5 | 4 | 1 |
| 6 | 4 | 2 |
| 7 | 4 | 4 |
|------------------------------|
|--------------------------------------|
| tbl_BookedHours |
|--------------------------------------|
| ID | fk_Project | Hours | Date |
|--------------------------------------|
| 1 | 1 | 10 | 2020-01-15 |
| 2 | 1 | 20 | 2020-01-20 |
| 3 | 2 | 10 | 2020-01-15 |
| 4 | 3 | 30 | 2020-01-18 |
| 5 | 2 | 20 | 2020-01-20 |
| 6 | 4 | 30 | 2020-01-25 |
| 7 | 1 | 10 | 2020-02-15 |
| 8 | 1 | 20 | 2020-02-20 |
| 9 | 2 | 10 | 2020-02-15 |
| 10 | 3 | 30 | 2020-03-18 |
| 11 | 2 | 20 | 2020-03-20 |
| 12 | 4 | 30 | 2020-03-25 |
|--------------------------------------|
The Result should be:
|----------------------------|
| fk_Product | Month | Hours |
|----------------------------|
| 1 | 1 | 55 |
| 2 | 1 | 25 |
| 3 | 1 | 30 |
| 4 | 1 | 10 |
| 1 | 2 | 25 |
| 2 | 2 | 15 |
| 1 | 3 | 30 |
| 2 | 3 | 10 |
| 3 | 3 | 30 |
| 4 | 3 | 10 |
|----------------------------|
For example booking Nr. 1 has to be divided by 2 (because Project 1 has two products) and one half of amount added to Product 1 and the other to Product 2 (Both in January). Booking Nr. 4 should not be divided, because Project 3 only has one product. Booking Numer 12 for example has to be divided by 3.
So that in total the Hours in the end add up to the same total.
I hope it's clearer now.
*** EDIT 2***
DECLARE #tbl_Projects TABLE (ID INT, [Name] VARCHAR(MAX))
INSERT INTO #tbl_Projects VALUES
(1,'Project 1'),
(2,'Project 2'),
(3,'Project 3'),
(4,'Project 4')
DECLARE #tbl_Products TABLE (ID INT, [Name] VARCHAR(MAX))
INSERT INTO #tbl_Products VALUES
(1,'Product 1'),
(2,'Product 2'),
(3,'Product 3'),
(4,'Product 4')
DECLARE #tbl_ProjectProduct TABLE (ID INT, fk_Project int, fk_Product int)
INSERT INTO #tbl_ProjectProduct VALUES
(1,1,1),
(2,1,2),
(3,2,1),
(4,3,3),
(5,4,1),
(6,4,2),
(7,4,4)
DECLARE #tbl_BookedHours TABLE (ID INT, fk_Project int, Hours int, [Date] Date)
INSERT INTO #tbl_BookedHours VALUES
(1,1,10,'2020-01-15'),
(2,1,20,'2020-01-20'),
(3,2,10,'2020-01-15'),
(4,3,30,'2020-01-18'),
(5,2,20,'2020-01-20'),
(6,4,30,'2020-01-25'),
(7,1,10,'2020-02-15'),
(8,1,20,'2020-02-20'),
(9,2,10,'2020-02-15'),
(10,3,30,'2020-03-18'),
(11,2,20,'2020-03-20'),
(12,4,30,'2020-03-25')
SELECT P.ID AS fk_Product, MONTH(B.Date) AS Month, SUM(B.Hours) AS SumHours
FROM #tbl_BookedHours AS B INNER JOIN #tbl_Projects AS M on B.fk_Project = M.ID
INNER JOIN #tbl_ProjectProduct AS PP ON PP.fk_Project = M.ID
INNER JOIN #tbl_Products AS P ON PP.fk_Product = P.ID
GROUP BY P.ID,MONTH(B.Date)
ORDER BY P.ID, MONTH(B.Date)
This gives me the wrong result, because it Counts the hours for both products:
| fk_Product | Month | SumHours |
|-------------------------------|
| 1 | 1 | 90 |
| 1 | 2 | 40 |
| 1 | 3 | 50 |
| 2 | 1 | 60 |
| 2 | 2 | 30 |
| 2 | 3 | 30 |
| 3 | 1 | 30 |
| 3 | 3 | 30 |
| 4 | 1 | 30 |
| 4 | 3 | 30 |
|-------------------------------|
Consider the following query. I modified your table variables to temp tables so it was easier to debug.
;WITH CTE AS
(
SELECT fk_Project, count(fk_Product) CNT
FROM #tbl_ProjectProduct
GROUP BY fk_Project
)
,CTE2 AS
(
SELECT t1.Date, t2.fk_Project, Hours/CNT NewHours
FROM #tbl_BookedHours t1
INNER JOIN CTE t2 on t1.fk_Project = t2.fk_Project
)
SELECT t4.ID fk_Product, MONTH(date) MN, SUM(NewHours) HRS
FROM CTE2 t1
INNER JOIN #tbl_Projects t2 on t1.fk_Project = t2.id
INNER JOIN #tbl_ProjectProduct t3 on t3.fk_Project = t2.ID
INNER JOIN #tbl_Products t4 on t4.ID = t3.fk_Product
GROUP BY t4.ID,MONTH(date)

Min Max (Date Time) And Count Data

Using SQL Server 2014
Example Table:
| ID | Date_Time | ID_Plan |
| 1 | 2018-12-19 21:21:00.000 | A1 |
| 2 | 2018-12-19 21:22:00.000 | A1 |
| 3 | 2018-12-19 21:23:00.000 | NULL |
| 4 | 2018-12-19 21:24:00.000 | NULL |
| 5 | 2018-12-19 21:25:00.000 | A2 |
| 6 | 2018-12-19 21:26:00.000 | A2 |
| 7 | 2018-12-19 21:27:00.000 | A2 |
| 8 | 2018-12-19 21:28:00.000 | A3 |
| 9 | 2018-12-19 21:29:00.000 | A3 |
| 10 | 2018-12-19 21:30:00.000 | NULL |
| 11 | 2018-12-19 21:31:00.000 | NULL |
| 12 | 2018-12-19 21:32:00.000 | NULL |
| 13 | 2018-12-19 21:33:00.000 | A4 |
| 14 | 2018-12-19 21:34:00.000 | A4 |
| 15 | 2018-12-19 21:35:00.000 | A4 |
| 16 | 2018-12-20 21:36:00.000 | NULL |
IF OBJECT_ID('tempdb..#tb_CountFinal') IS NOT NULL
DROP TABLE #tb_CountFinal
CREATE TABLE #tb_CountFinal
(
[ID] [int] IDENTITY(1,1) NOT NULL,
Date_Time DATETIME,
ID_Plan NVARCHAR(100)
)
INSERT INTO #tb_CountFinal
SELECT '12/19/2018 21:21','A1'union all
SELECT '12/19/2018 21:22','A1'union all
SELECT '12/19/2018 21:23',NULL union all
SELECT '12/19/2018 21:24',NULL union all
SELECT '12/19/2018 21:25','A2'union all
SELECT '12/19/2018 21:26','A2'union all
SELECT '12/19/2018 21:27','A2'union all
SELECT '12/19/2018 21:28','A3'union all
SELECT '12/19/2018 21:29','A3'union all
SELECT '12/19/2018 21:30',NULL union all
SELECT '12/19/2018 21:31',NULL union all
SELECT '12/19/2018 21:32',NULL union all
SELECT '12/19/2018 21:33','A4'union all
SELECT '12/19/2018 21:34','A4'union all
SELECT '12/19/2018 21:35','A4'union all
SELECT '12/20/2018 21:36',NULL
I'm interested in a query which would output rows similar to the following:
| Start_Date | End_Date | Plan_ID | Count_PlantID |
| 12/19/2018 21:21 | 12/19/2018 21:22 | A1 | 2 |
| 12/19/2018 21:23 | 12/19/2018 21:24 | NULL | 2 |
| 12/19/2018 21:25 | 12/19/2018 21:27 | A2 | 3 |
| 12/19/2018 21:28 | 12/19/2018 21:29 | A3 | 2 |
| 12/19/2018 21:30 | 12/19/2018 21:32 | NULL | 3 |
| 12/19/2018 21:33 | 12/19/2018 21:35 | A4 | 3 |
| 12/20/2018 21:36 | 12/20/2018 21:36 | NULL | 1 |
For each NULL entries I made a key by looking at the previous starting [ID] column, then performed the Group By on that new column. Try it.
select min(Date_Time) as Start_Date, max(Date_Time) as End_Date
, min(ID_Plan) as Plan_ID, count(1) as Count_PlanID
from (
select s.*
, case when ID_Plan is null
then
cast(
(
select max([ID])
from #tb_CountFinal as x
where x.ID < s.ID and ID_Plan is not null
) as varchar(100)
)
else
ID_Plan
end as ID_Plan_Adv_Start
from #tb_CountFinal as s
) as dt
group by dt.ID_Plan_Adv_Start
order by Start_Date

Select all rows in Table 1 and filling columns of Table 2

I have two tables as follows:
Table1:
ID | FName | LName
1 | A1 | A2
2 | B1 | B2
3 | C1 | C2
Table2:
ID | Price | Month | T1ID
1 | 5 | 1 | 1
2 | 5 | 1 | 2
3 | 5 | 2 | 3
Result:
Where Month = '1'
ID | FName | LName | Price | Month | T1ID
1 | A1 | A2 | 5 | 1 | 1
2 | B1 | B2 | 5 | 1 | 2
NULL| C1 | C2 | NULL | NULL | 3
Where Month = '2'
ID | FName | LName | Price | Month | T1ID
NULL| A1 | A2 | NULL | NULL | 1
NULL| B1 | B2 | NULL | NULL | 2
3 | C1 | C2 | 5 | 2 | 3
Looks like a left join with multiple join conditions:
SELECT t2.ID, t1.FName, t1.LName, t2.Price, t2.Month, t1.ID
FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.ID = t2.T1ID AND t2.Month = '1' -- or '2'
The trick is to do filtering by adding additional condition to ON clause, which helps to filter records during the join. If you used the condition in WHERE clause, some records would be filtered out from the results, which is not what you expect.

Resources