Linking tables on date basis - sql-server

I am having two tables as below
Child_Attendance
childid updatedon presentdays
1 31/01/2018 20
1 28/02/2018 15
1 31/03/2018 18
1 30/04/2018 24
1 31/05/2018 17
1 30/06/2018 19
2 31/03/2018 25
2 30/04/2018 28
2 31/05/2018 22
2 30/06/2018 23
And the Second table as
childid class admissiondate
1 creches 15/06/2017
1 balwari 01/02/2018
2 creches 01/01/2017
2 balwari 01/01/2018
2 Bridge Course 01/04/2018
Now, I need a query to return childid,updatedon,presentdays,class.
I am new to sql and don't have any idea how to do it.
I have tried
SELECT t1.childid,t1.updatedon,t1.presentdays,t2.class
FROM child_attendance t1 LEFT JOIN class_allocation t2
ON t1.childid = t2.childid
AND t1.updatedon >= t2.admissiondate
My output should be like this
You can see the child 1 was admitted in creche on dated 15/06/2017 and balwari on dated 01/02/2018. This means he was in creche from 15/06/2018 till 01/02/2018.

I think this query could get what you want:
SELECT t1.childid, t1.updatedon, t1.presentdays,
class=(SELECT TOP (1) class
FROM Class_Allocation
WHERE childid=t1.childid
AND t1.updatedon>=admissiondate
ORDER BY admissiondate DESC)
FROM Child_Attendance t1

Related

Repeat a sum as a column in SQL

I have a table
WO# Seg# Part# QTY TotSale FlatSale
1 1 1 5 35 159
1 1 2 2 100 159
1 2 3 3 50 50
I need to calculate the FlatSale/SUM(TotSale) for each Seq# & WO# but do not group Seg# into one row.
I need this
WO# Seg# Part# QTY TotSale FlatSale Calc
1 1 1 5 35 159 1.177
1 1 2 2 100 159 1.177
1 2 3 3 50 50 1
With my code I am able to only do the division on each individual line like this:
select *, FlatSale/TotSale as Calc from table
WO# Seg# Part# QTY TotSale FlatSale Calc
1 1 1 5 35 159 4.54
1 1 2 2 100 159 1.59
1 2 3 3 50 50 1
I wouldn't mind leaving my Calc column and adding another column if that's the easiest way to do it.
Maybe something like this:
SELECT
[WO#],[Seg#],[Part#],[QTY],[TotSale],[FlatSale]
((FlatSale*100)/(SUM([TotSale]) OVER(PARTITION BY [Seg#] ORDER BY [Seg#])))/100 AS Calc
FROM SomeTable
You can use a lateral join. Here's something quick (not tested as I don't have access to mssql at the moment):
select *, x.CalcPrice as Calc
from table t
outer apply (
select t.FlatSale/SUM(ix.TotSale) CalcPrice
from table ix where ix.[WO#] = t.[WO#]
and ix.[Seg#] = t.[Seg#]) x
Something like that.

SQL select joined 2 tables same as one column

SQL table Authority is:
AuthorNo Price PrePay(bit)
----------------------------
1 250$ 1
2 120$ 0
3 300$ 0
4 112$ 1
5 25$ 0
Table Order is:
AuthorNo OrderNo
-----------------
1 33
1 34
2 33
2 38
3 41
3 82
4 55
4 21
5 21
5 66
I want the result is:
Select from Authority.AuthorNo where AuthorNo same in Order.OrderNo and at least one of the AuthorNo.Prepay is 1
AuthorNo
--------
1
2
4
5
How to select this?
If you need to find the authors that have orders that were also ordered by authors with PrePay?
Then you could use an EXISTS for this.
SELECT auth.AuthorNo
FROM Authority auth
JOIN [Order] ord ON ord.AuthorNo = auth.AuthorNo
WHERE EXISTS
(
SELECT 1
FROM [Order] ord_pp
JOIN Authority auth_pp
ON auth_pp.AuthorNo = ord_pp.AuthorNo
AND auth_pp.Prepay = 1
WHERE ord_pp.OrderNo = ord.OrderNo
)
GROUP BY auth.AuthorNo;
A test here
Result:
AuthorNo
--------
1
2
4
5
I am guessing you just want to see the AuthorNo in the result? Try this
Select distinct a.AuthorNo
From Authority a
join Order b on a.AuthorNo=b.AuthorNo
where a.Prepay=1

T-SQL query to write case statements with different scenarios

I have 2 tables Test Table and Investigation table.
Test table has
ChildID AddressID TestID TestValue TestDate
1 1 1 20 08/04/2017
2 2 2 20 09/04/2017
2 2 3 10 10/04/2017
When a child has test value >=20 the system automatically generates a Investigation on address but cannot open when between 15 and 19.9
Investigation Table
ChildID InvestID AddressID Status
1 1 1 open
2 2 2 open
If I get a new incoming Test record for child id's this is how my table looks
ChildID AddressID TestID TestValue TestDate
1 1 1 20 08/04/2017
1 5 4 16 12/04/2017(New record)
2 2 2 20 09/04/2017
2 2 3 10 10/04/2017
2 3 5 19 12/04/2017(New Record)
Scenario 1
I want to select New records and show 'status'(new column) as 'New address' case where Test value is between 15 and 19.9 and test date is 90 days apart and address id is not equal for two tests. Don't select any record if the address is same.
Scenario 2
If the child has second testvalue between 15 and 19.9 with same addess id
ChildID AddressID TestID TestValue TestDate
3 6 10 16 08/04/2017
3 6 20 18 11/04/2017 (New Record)
Select the new records with status as 'New Case and New address'
Scenario 3
ChildID AddressID TestID TestValue TestDate
3 6 10 16 08/04/2017
3 6 20 18 11/04/2017
3 7 21 17 02/04/2018 (New record)
Show latest record status as 'new address' because it has different address.
So far I have written the query but I am unable to compare records and write case statements for 'Status column'. I am only able to select records.
Select childid,Testid,TestDate,
TestValue,addressid,lc.caseType,
DateDiff(Day,lead(Test) OVER (Partition by Childid order by TestDate desc),Testdate) as Datediff,
DateDiff(day,First_Value(Testdate) Over (Partition by Childid order by b2.Testdateasc),Testdate) as Datedif1
from Test T
Left Join Investigation I
on T.child=I.childid
and b.observationValue between 15 and 19.99
and Datedif1>=90 or Datediff>=90

Transact SQL - which Join to Use

I have two simple SELECT statements:
The first shows a list of Features.
SELECT * FROM Features
id name
-- ----
1 24 Hour Access
2 24 hour CCTV monitoring
3 Airport location
4 Break-Out Areas
5 Business Lounge
6 Business park location
snip..
and the second statement shows a list of feature information that has changed
SELECT
*
FROM
#SmartFeaturesToUpdate new_features
ORDER BY
new_features.centre_translation_id,
new_features.feature_id,
new_features.feature_selected
feature_id centre_translation_id feature_selected
---------- --------------------- ----------------
1 1 1
2 1 1
5 1 1
10 1 1
11 1 1
snip..
What I want to see is all of the features by centre translation.
Combining the tables gives me:
SELECT
*
FROM
#SmartFeaturesToUpdate new_features
LEFT JOIN Feature feature ON feature.id = new_features.feature_id
ORDER BY
new_features.centre_translation_id,
new_features.feature_id,
new_features.feature_selected
feature_id centre_translation_id feature_selected id name
---------- --------------------- ---------------- -- ----
1 1 1 1 24 Hour Access
2 1 1 2 24 hour CCTV monitoring
5 1 1 5 Business Lounge
10 1 1 10 Double Glazing
11 1 1 11 Elevator
snip..
The result above is missing feature id's 3 and 4, because they are not in the second list.
but the result I need is:
feature_id centre_translation_id feature_selected id name
---------- --------------------- ---------------- -- ----
1 1 1 1 24 Hour Access
2 1 1 2 24 hour CCTV monitoring
3 1 1 3 Airport Location
4 1 1 4 Break-Out Area
5 1 1 5 Business Lounge
snip..
How should I modify the third SELECT statement to acheive this and combine the results from both the features and feature information list?
As the comments alluded, I needed another table which linked Features to centre_translation_ids
First get all of the feature / centre_translation varients
SELECT
[centre_translation_id] = centre_translation.id,
feature.id,
feature.name
INTO #AllTheFeatures
FROM
CentreTranslation centre_translation
CROSS JOIN Feature feature
ORDER BY
centre_translation.id,
feature.id
Now we can simply perform the LEFT JOIN
SELECT
all_features.centre_translation_id,
all_features.id,
all_features.name,
smart_features.feature_selected
FROM
#AllTheFeatures all_features
LEFT JOIN #SmartFeaturesToUpdate smart_features ON smart_features.centre_translation_id = all_features.centre_translation_id AND
smart_features.feature_id = all_features.id
ORDER BY
all_features.centre_translation_id,
all_features.id
This gives the results:
centre_translation_id id name feature_selected
--------------------- -- ---- ----------------
1 1 24 Hour Access 1
1 2 24 hour CCTV monitoring 1
1 3 Airport location NULL
1 4 Break-Out Areas NULL
1 5 Business Lounge 1
Why don't you just put it in one query?
SELECT
centre_translation.id AS centre_translation_id,
feature.id,
feature.name,
smart_features.feature_selected
FROM
CentreTranslation centre_translation
CROSS JOIN Feature feature
LEFT JOIN #SmartFeaturesToUpdate smart_features
ON smart_features.centre_translation_id = all_features.centre_translation_id
AND smart_features.feature_id = all_features.id
ORDER BY
centre_translation.centre_translation_id,
feature.id

Add dynamic column in select query - MS SQL

Im using Ms SQL database,
My table looks,
SrNo Emp_ID Date Time
------------------------------------
1 25 03-Sep-12 9:35:35 AM
2 25 03-Sep-12 10:31:32 AM
3 25 03-Sep-12 10:34:13 AM
4 25 03-Sep-12 11:05:08 AM
5 25 03-Sep-12 11:08:39 AM
6 25 04-Sep-12 09.05.40 AM
The expected output is
SrNo Emp_ID Date Time Type
---------------------------------------------
1 25 03-Sep-12 9:35:35 AM IN
2 25 03-Sep-12 10:31:32 AM OUT
3 25 03-Sep-12 10:34:13 AM IN
4 25 03-Sep-12 11:05:08 AM OUT
5 25 03-Sep-12 11:08:39 AM IN
6 25 04-Sep-12 09.05.40 AM IN
For an employee, type "in" and "out" has to be added simultaneously for particular date. For the next date or next /same employee, type has to start with "IN". Can any 1 help me in writing the sql query.
You can achieve this using an additional column
ROW_NUMBER() OVER (PARTITION BY Emp_ID, Date ORDER BY Time) AS RN
then checking modulus 2 on it, if remainder is 1, it's an IN, if it's 0 it's an OUT, based on your requirements.
More specifically
CASE WHEN
ROW_NUMBER() OVER (PARTITION BY Emp_ID, Date ORDER BY Time) % 2 = 1
THEN 'IN'
ELSE 'OUT'
END AS [Type]

Resources