Sql server query clarification - sql-server

I have table like below,
Txn_Id Txn_Type
___________________
1 101
1 102
1 103
1 104
2 101
2 102
2 104
3 101
3 104
I want rows which has only txn_type 101 and 104. For eg., I should get only Txn_Id "3" for above data.
I tried like below and getting result. Is it possible to have single query to achive this.
Select txn_id from Txn where txn_id in (Select txn_id from Txn where txn_id = 101) and txn_id =104.

Select txn_id from Txn where txn_type in (101,104)
option 2
Select txn_id from Txn where (txn_type = 101 OR txn_type=104)
To get only "3"
Select distinct txn_id from Txn t1 where (txn_type = 101 OR txn_type=104)
and not exists(
select 1 from Txn t2 where t2.txn_type IN (102,103) and t2.txn_id = t1.txn_id
)

Hi As per your above comments you only need the txn_id =3(max)
Please Find the code below.
DECLARE #Table1 TABLE
(txn_id int, Txn_Type int)
;
INSERT INTO #Table1
(txn_id , Txn_Type )
VALUES
(1, 101),
(1, 102),
(1, 103),
(1, 104),
(2, 101),
(2, 102),
(2, 104),
(3, 101),
(3, 104)
;
Select max(txn_id ),Txn_Type
from #Table1 where item in (101,104)
group by Txn_Type

As balaji pointed out, #Ayush solution is not flexible, since will return incorrect results if you, for example, add another pair of records in the table (4,101) and (4,104). IMO, you have to join table to itself for some filtering, something like this:
DECLARE #Table1 TABLE
(txn_id int, Txn_Type int);
INSERT INTO #Table1
(txn_id , Txn_Type )
VALUES
(1, 101),
(1, 102),
(1, 103),
(1, 104),
(2, 101),
(2, 102),
(2, 104),
(3, 101),
(3, 104),
(4, 101),
(4, 104);
select t1.*
from #Table1 t1
inner join (select txn_id, count(*) as total
from #Table1
group by Txn_id
having count(*) < 3
) t2 on t2.txn_id = t1.txn_id
where t1.Txn_Type in (101,104)

Related

Question about subqueries with specific conditions and same condition as query at the same time

I am using T-SQL for a few months and there is one thing I simply don't know how to do. Let's say we have a table created below
DECLARE #table TABLE
(
id int,
status_FK int,
[value] int
)
INSERT INTO #table (id, status_FK, [value])
VALUES (1, 1, 1000),
(2, 1, 2000),
(3, 2, 3000),
(4, 1, 2000),
(5, 2, 2000),
(6, 2, 3000),
(7, 5, 12000)
SELECT
(SELECT SUM(value) WHERE status_FK = 1) AS 'status1',
(SELECT SUM(value) WHERE status_FK = 2) AS 'status2'
FROM
#table
WHERE
value > 1500
What I'm trying to do is use condition value > 1500 for all subqueries but also each subquery have specific condition. Can someone please explain me how to do this simple thing without repeating whole main query in both subqueries with different conditions? Many thanks <3
Probably something like that:
SELECT
SUM(case when status_FK = 1 then value else 0 end) as `status1`,
SUM(case when status_FK = 2 then value else 0 end) as `status2`
FROM #table
WHERE value > 1500
Update 1:
You can have many as you like, best if you have small of column to display:
SELECT
SUM(case when status_FK = 1 then value else 0 end) as `status1`,
SUM(case when status_FK = 2 then value else 0 end) as `status2`,
...
SUM(case when status_FK = n then value else 0 end) as `statusn`,
FROM #table
WHERE value > 1500
For complex cases you can look at PIVOT.
You can try using Join also
SELECT Status_fk
,sum(value)
FROM #table t
INNER JOIN (
VALUES (1)
,(2)
) X(StatusID) ON t.status_FK = X.StatusID
WHERE value > 1500
GROUP BY status_FK
You can use PIVOT, a powerful operator.
CREATE TABLE #TEMP
(
id int,
status_FK int,
[value] int
)
INSERT INTO #TEMP (id, status_FK, [value])
VALUES (1, 1, 1000),
(2, 1, 2000),
(3, 2, 3000),
(4, 1, 2000),
(5, 2, 2000),
(6, 2, 3000),
(7, 5, 12000)
SELECT [1] AS status1, [2] AS status2
FROM (SELECT status_FK, value FROM #TEMP WHERE value > 1500) AS T
PIVOT(SUM([value]) FOR status_FK IN ([1], [2])) AS PT

Filter Table Before Applying Right Join ON 3RD TABLE

Using MSSQL: Just for clarification
Customer Table
CustomerNumber Name
===================
1 David
2 Thomas
3 Mangold
4 Issac
------------------------------------------------------------
CustomerAddress Table
CustomerNumber State EffectiveDate
==================================
1 AL 01/01/2017
1 VA 06/01/2017
1 GA 02/01/2018
1 FL 10/01/2018
2 TX 01/01/2017
3 MA
4 IL 04/01/2015
SalesOrder Table
CUSTOMER ORDERNo OrderDate
========================
1 1000 03/01/2017
2 1001 10/10/2017
1 1002 11/01/2017
3 1003 12/01/2017
4 1004 01/01/2018
1 1005 02/01/2018
1 1006 01/01/2019
I need to fetch all the orders with the customer detail and the customer address on the order date.
SELECT T1.ORDERNo, T1.ORDERDATE, T1.CUSTOMER, T2.NAME, T3.STATE
FROM SALESORDER T1, CUSTOMER T2, CUSTOMERADDRESS T3
RIGHT JOIN(
SELECT CUSTOMER, MAX(EFFECTIVEDATE) FROM CUSTOMERADDRESS
--WHERE EFFECTIVEDATE <= T1.ORDERDATE
GROUP BY CUSTOMER)T4
ON T3.CUSTOMER = T4.CUSTOMER AND T3.EFFECTIVEDATE=T4.EFFECTIVEDATE
WHERE T1.CUSTOMER = T2.CUSTOMERNUMBER
AND T1.CUSTOMER = T3.CUSTOMERNUMBER
Want to see how to do compare in the join where i compare first table to the 3rd table in the join. see the commented code --WHERE EFFECTIVEDATE <= T1.ORDERDATE
If I remove the commented code, the table in the join cannot reference a table outside.
The expected output is:
CUSTOMER ORDERNo OrderDate CustomerName State
=============================================
1 1000 03/01/2017 David AL
2 1001 10/10/2017 Thomas TX
1 1002 11/01/2017 David VA
3 1003 12/01/2017 Mangold MA
4 1004 01/01/2018 Issac IL
1 1005 02/01/2018 David GA
1 1006 01/01/2019 David FL
The tables in sql fiddle http://sqlfiddle.com/#!18/9eecb:
CREATE TABLE Customer
('CustomerNumber' int, 'CustomerName' varchar(30))
;
INSERT INTO Customer
('CustomerNumber', 'CustomerName')
VALUES
(1, 'David'),
(2, 'Thomas'),
(3, 'Mangold'),
(4, 'Issac')
;
CREATE TABLE CustomerAddress
('CustomerNumber' int, 'State' varchar(2), 'EffectiveDate' date)
;
INSERT INTO CustomerAddress
('CustomerNumber', 'State', 'EffectiveDate')
VALUES
(1, 'AL', 01/01/2017),
(1, 'VA', 06/01/2017),
(1, 'GA', 02/01/2018),
(1, 'FL', 10/01/2018),
(2, 'TX', 01/01/2017),
(3, 'MA',),
(4, 'IL', 04/01/2015)
;
CREATE TABLE SalesOrder
('CUSTOMER' int, 'ORDERNO' int, 'OrderDate' Date)
;
INSERT INTO SalesOrder
('CUSTOMER', 'ORDERNO', 'OrderDate')
VALUES
(1, 1000, 03/01/2017),
(2, 1001, 10/10/2017),
(1, 1002, 11/01/2017),
(3, 1003, 12/01/2017),
(4, 1004, 01/01/2018),
(1, 1005, 02/01/2018),
(1, 1006, 01/01/2019)
;
CREATE TABLE CustomerAddress
(`CustomerNumber` int, 'State' varchar(2), `EffectiveDate` date)
;
INSERT INTO CustomerAddress
(`CustomerNumber`, `State`, 'EffectiveDate')
VALUES
(1, 'AL', 01/01/2017),
(1, 'VA', 06/01/2017),
(1, 'GA', 02/01/2018),
(1, 'FL', 10/01/2018),
(2, 'TX', 01/01/2017),
(3, 'MA',),
(4, 'IL', 04/01/2015)
;
CREATE TABLE SalesOrder
(`CUSTOMER` int, 'ORDERNO' int, `OrderDate` Date)
;
INSERT INTO SalesOrder
(`CUSTOMER `, `ORDERNO`, 'OrderDate')
VALUES
(1, 1000, 03/01/2017),
(2, 1001, 10/10/2017),
(1, 1002, 11/01/2017),
(3, 1003, 12/01/2017),
(4, 1004, 01/01/2018),
(1, 1005, 02/01/2018),
(1, 1006, 01/01/2019)
;
'sql server version'
CREATE TABLE Customer
(CustomerNumber int, CustomerName varchar(30))
;
INSERT INTO Customer
(CustomerNumber, CustomerName)
VALUES
(1, 'David'),
(2, 'Thomas'),
(3, 'Mangold'),
(4, 'Issac');
;
CREATE TABLE CustomerAddress
(CustomerNumber int, State varchar(2), EffectiveDate date)
;
INSERT INTO CustomerAddress
(CustomerNumber, State, EffectiveDate)
VALUES
(1, 'AL', '01/01/2017'),
(1, 'VA', '06/01/2017'),
(1, 'GA', '02/01/2018'),
(1, 'FL', '10/01/2018'),
(2, 'TX', '01/01/2017'),
(4, 'IL', '04/01/2015')
;
INSERT INTO CustomerAddress
(CustomerNumber, State)
VALUES
(3, 'MA' )
;
CREATE TABLE SalesOrder
(CUSTOMER int, ORDERNO int, OrderDate Date)
;
INSERT INTO SalesOrder
(CUSTOMER, ORDERNO, OrderDate)
VALUES
(1, 1000, '03/01/2017'),
(2, 1001, '10/10/2017'),
(1, 1002, '11/01/2017'),
(3, 1003, '12/01/2017'),
(4, 1004, '01/01/2018'),
(1, 1005, '02/01/2018'),
(1, 1006, '01/01/2019')
;
The problem: Need to Pick all the Sales Orders and their customer Name, and the Customer Address. The important and tricky part is the customer address changes based on the date of the sales order.
--MODIFIED VERSION OF THE INCOMPLETE QUERY
SELECT T1.ORDERNo, T1.ORDERDATE, T1.CUSTOMER, T2.CustomerName, T3.STATE
FROM CUSTOMER T2, SALESORDER T1 INNER JOIN CUSTOMERADDRESS T3 ON T1.CUSTOMER = T3.CUSTOMERNUMBER
RIGHT JOIN(
SELECT CustomerNumber, MAX(EFFECTIVEDATE) as EffectiveDate4 FROM CUSTOMERADDRESS
--WHERE EFFECTIVEDATE < T1.ORDERDATE
GROUP BY CustomerNumber
--HAVING EFFECTIVEDATE < T1.ORDERDATE
) T4
ON T3.CustomerNumber = T4.CustomerNumber AND T3.EFFECTIVEDATE=T4.EffectiveDate4
WHERE T1.CUSTOMER = T2.CUSTOMERNUMBER
OUTER APPLY should solve your problem. based on your needs you can change your query.
SELECT T1.ORDERNo, T1.ORDERDATE, T1.CUSTOMER, T2.NAME, T3.STATE
FROM SALESORDER T1, CUSTOMER T2, CUSTOMERADDRESS T3
OUTER APPLY(
SELECT CUSTOMER, MAX(EFFECTIVEDATE) FROM CUSTOMERADDRESS
WHERE EFFECTIVEDATE <= T1.ORDERDATE
AND T3.CUSTOMER = CUSTOMER )T4
WHERE T1.CUSTOMER = T2.CUSTOMERNUMBER
AND T1.CUSTOMER = T3.CUSTOMERNUMBER
AND T3.EFFECTIVEDATE = T4.EFFECTIVEDATE

how to select and join same table in mssql [duplicate]

I have a simple categories table as with the following columns:
Id
Name
ParentId
So, an infinite amount of Categories can be the child of a category. Take for example the following hierarchy:
I want, in a simple query that returns the category "Business Laptops" to also return a column with all it's parents, comma separator or something:
Or take the following example:
Recursive cte to the rescue....
Create and populate sample table (Please save us this step in your future questions):
DECLARE #T as table
(
id int,
name varchar(100),
parent_id int
)
INSERT INTO #T VALUES
(1, 'A', NULL),
(2, 'A.1', 1),
(3, 'A.2', 1),
(4, 'A.1.1', 2),
(5, 'B', NULL),
(6, 'B.1', 5),
(7, 'B.1.1', 6),
(8, 'B.2', 5),
(9, 'A.1.1.1', 4),
(10, 'A.1.1.2', 4)
The cte:
;WITH CTE AS
(
SELECT id, name, name as path, parent_id
FROM #T
WHERE parent_id IS NULL
UNION ALL
SELECT t.id, t.name, cast(cte.path +','+ t.name as varchar(100)), t.parent_id
FROM #T t
INNER JOIN CTE ON t.parent_id = CTE.id
)
The query:
SELECT id, name, path
FROM CTE
Results:
id name path
1 A A
5 B B
6 B.1 B,B.1
8 B.2 B,B.2
7 B.1.1 B,B.1,B.1.1
2 A.1 A,A.1
3 A.2 A,A.2
4 A.1.1 A,A.1,A.1.1
9 A.1.1.1 A,A.1,A.1.1,A.1.1.1
10 A.1.1.2 A,A.1,A.1.1,A.1.1.2
See online demo on rextester

SQL Server: max of date

Table 1
RefId Name
----- ----
1 A
2 B
Table 2
RefId Date
----- -----
1 29/03/2018 07:15
1 29/03/2018 07:30
2 29/03/2018 07:35
2 29/03/2018 07:40
I would like the result to be as follows (Refid name and the max(date) from table 1 and 2 for that refid)
1 A 29/03/2018 07:30
2 B 29/03/2018 07:40
Query used
select
table1.refId, table1.name,
(select max(date) from table2)
from
table1, table2
where
table1.refid = table2.refid
group by
table2.refid
I am getting the following error message
Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Use JOIN and the aggregate function MAX with GROUP BY to select the max date for each RefId.
Query
select [t1].[RefId], [t1].[Name], max([t2].[date] as [date]
from [Table1] [t1]
join [Table2] [t2]
on [t1].[RefId] = [t2].[RefId]
group by [t1].[RefId], [t1].[Name];
'29/03/2018 07:15' is nvarchar-type, you need datetime.
nvarchar convert to datetime: SELECT CONVERT(datetime, '29/03/2018 07:15', 103)
Answer to your example:
DECLARE #Table1 TABLE(RefId int, Name nvarchar(10));
INSERT INTO #Table1(RefId, Name) VALUES(1, 'A'), (2, 'B');
DECLARE #Table2 TABLE(RefId int, [Date] nvarchar(50));
INSERT INTO #Table2(RefId, [Date])
VALUES
(1, '29/03/2018 07:15'),
(1, '29/03/2018 07:30'),
(2, '29/03/2018 07:35'),
(2, '29/03/2018 07:40');
SELECT t1.RefId, t1.Name, t2.Date
FROM #Table1 AS t1
INNER JOIN
(SELECT RefId, MAX(CONVERT(datetime, [Date], 103)) AS [Date]
FROM #Table2
GROUP BY RefId) AS t2
ON t1.RefId = t2.RefId

Finding a date gap (missing date range) within a SQL table

On this SQL Server 2008 database I have a table of attendance, students come into school every day and check in, the table looks something like this:
SchoolID | StudentID | Date
There will be a record for every day for every student on this table. What I want to find out is, given a start date, an end date, and a number of days (gap), find any student that has not checked into school for that number of days. So for example, I need to know which students missed 3 days straight during the month of December, and spit out the list of StudentIDs.
How can I accomplish something like that?
You can produce date ranges from startdate to enddate
then outer join this data with your table, if the student wouldn't have come consider it as 1 then summarize this data.
for generating date range you can use this function as below
CREATE FUNCTION [dbo].[DateRange]
(
#Increment CHAR(1),
#StartDate DATETIME,
#EndDate DATETIME
)
RETURNS
#SelectedRange TABLE
(IndividualDate DATETIME)
AS
BEGIN
;WITH cteRange (DateRange) AS (
SELECT #StartDate
UNION ALL
SELECT
CASE
WHEN #Increment = 'd' THEN DATEADD(dd, 1, DateRange)
WHEN #Increment = 'w' THEN DATEADD(ww, 1, DateRange)
WHEN #Increment = 'm' THEN DATEADD(mm, 1, DateRange)
END
FROM cteRange
WHERE DateRange <=
CASE
WHEN #Increment = 'd' THEN DATEADD(dd, -1, #EndDate)
WHEN #Increment = 'w' THEN DATEADD(ww, -1, #EndDate)
WHEN #Increment = 'm' THEN DATEADD(mm, -1, #EndDate)
END)
INSERT INTO #SelectedRange (IndividualDate)
SELECT DateRange
FROM cteRange
OPTION (MAXRECURSION 3660);
RETURN
END
GO
then
select sum(isAbsent) absentDays, s.studentid from
(
select case when studentid is null then 1 else 0 end isAbsent,individualDate,s.studentid from DateRange('d', '01/11/2014', '30/11/2014') d
cross join tblstudent s
left outer join yourtable on yourtable.Date = d.IndividualDate and yourtable.studentid = s.studentid
) x
group by s.studentid
having sum(isAbsent) > 3
Just look at this. I think you will be able to figure out you own answer from that.This solution take care of the weekend days and holidays :
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE attendance
([SchoolID] int, [StudentID] int, [Date] datetime)
;
INSERT INTO attendance
([SchoolID], [StudentID], [Date])
VALUES
(1, 1, '2014-12-01 00:00:00'),
(1, 1, '2014-12-02 00:00:00'),
(1, 1, '2014-12-03 00:00:00'),
(1, 1, '2014-12-04 00:00:00'),
(1, 1, '2014-12-05 00:00:00'),
(1, 1, '2014-12-08 00:00:00'),
(1, 1, '2014-12-09 00:00:00'),
(1, 1, '2014-12-10 00:00:00'),
(1, 1, '2014-12-11 00:00:00'),
(1, 1, '2014-12-12 00:00:00'),
(1, 1, '2014-12-15 00:00:00'),
(1, 1, '2014-12-16 00:00:00'),
(1, 1, '2014-12-17 00:00:00'),
(1, 1, '2014-12-18 00:00:00'),
(1, 1, '2014-12-19 00:00:00'),
(1, 2, '2014-12-01 00:00:00'),
(1, 2, '2014-12-02 00:00:00'),
(1, 2, '2014-12-08 00:00:00'),
(1, 2, '2014-12-09 00:00:00'),
(1, 2, '2014-12-10 00:00:00'),
(1, 2, '2014-12-11 00:00:00'),
(1, 2, '2014-12-12 00:00:00'),
(1, 2, '2014-12-15 00:00:00'),
(1, 2, '2014-12-16 00:00:00'),
(1, 2, '2014-12-17 00:00:00'),
(1, 2, '2014-12-18 00:00:00'),
(1, 2, '2014-12-19 00:00:00')
;
CREATE TABLE holidays
([Date] datetime)
;
INSERT INTO holidays
([Date])
VALUES
('2014-12-22 00:00:00'),
('2014-12-23 00:00:00'),
('2014-12-24 00:00:00'),
('2014-12-25 00:00:00'),
('2014-12-26 00:00:00'),
('2014-12-29 00:00:00'),
('2014-12-30 00:00:00'),
('2014-12-31 00:00:00')
;
CREATE TABLE students
([StudentID] int, [Name] varchar(5))
;
INSERT INTO students
([StudentID], [Name])
VALUES
(1, 'John'),
(2, 'Peter')
;
Query 1:
DECLARE #start DATE, #end DATE
SELECT #start = '20141201', #end = '20141231'
;WITH tdate AS
(
SELECT TOP (DATEDIFF(DAY, #start, #end) + 1)
n = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_objects
)
SELECT DISTINCT Name
FROM students s
INNER JOIN attendance a ON s.StudentID = a.StudentID
INNER JOIN tdate ON DATEADD(DAY, n-1, #start) = a.Date
GROUP BY NAME
HAVING
(SELECT count(*)
FROM tdate
LEFT OUTER JOIN holidays h ON DATEADD(DAY, n-1, #start) = h.Date
WHERE h.date is null
AND DATEPART(dw,DATEADD(DAY, n-1, #start)) not in (1,7))
- COUNT(*) >= 3
Results:
| NAME |
|-------|
| Peter |
UPDATE
SELECT s.StudentID, d.Date
FROM students s
INNER JOIN (
SELECT DATEADD(DAY, n-1, #start) as Date
FROM tdate
LEFT OUTER JOIN holidays h ON DATEADD(DAY, n-1, #start) = h.Date
WHERE h.date is null
AND DATEPART(dw,DATEADD(DAY, n-1, #start)) not in (1,7)) d ON 1 = 1
LEFT OUTER JOIN attendance a ON s.StudentID = a.StudentID AND d.Date = a.Date
WHERE a.StudentID IS NULL
ORDER BY s.StudentID, d.Date
Results:
| STUDENTID | DATE |
|-----------|------------|
| 2 | 2014-12-03 |
| 2 | 2014-12-04 |
| 2 | 2014-12-05 |

Resources