How to Get current column value, Previous Column Value - sql-server

How to get Previous Column Value?
IIf id1 = id2 then display previous column id1 value
id1 id2
1001 1001
1002 1002
1003 1003
so on...
select id1, id2, Iff id2 = id1 then disply previous id1 value as idadjusted
Output
id1 id2 id3(Expected)
1001 1001 **1000**
1002 1002 **1001**
1003 1003 **1002**
so on...
I want to disply previous column value of id1
My query
SELECT CARDNO, NAME, TITLENAME, CARDEVENTDATE, MIN(CARDEVENTTIME) AS INTIME, MAX(CARDEVENTTIME) AS OUTTIME,
CARDEVENTDATE AS LASTDATE, MAX(CARDEVENTTIME) AS LASTTIME
FROM (SELECT T_PERSON.CARDNO, T_PERSON.NAME, T_TITLE.TITLENAME, T_CARDEVENT.CARDEVENTDATE, T_CARDEVENT.CARDEVENTTIME FROM (T_TITLE INNER JOIN T_PERSON ON T_TITLE.TITLECODE = T_PERSON.TITLECODE) INNER JOIN T_CARDEVENT ON T_PERSON.PERSONID = T_CARDEVENT.PERSONID ORDER BY T_PERSON.TITLECODE) GROUP BY CARDNO, NAME, TITLENAME, CARDEVENTDATE
For the LastDate - I want to Display Previous column cardeventdate value
For the Lasttime - I want to display previous column outtime value
Need Query Help?

The on clause is used to retrieve the previous id, I have tested it and works fine.
This solution will work even if intermediate ids are missiing i.e. ids are not consecutive
select t1.id, t1.column1, t1.column2,
case
when (t1.column1 = t1.column2) then t2.column1
else null
end as column3
from mytable t1
left outer join mytable t2
on t1.id = (select max(id) from mytable where id < t1.id)
For your complex query, you can create a view and then use the above sql format for your view:
Create a view MyView for:
SELECT CARDNO, NAME, TITLENAME, CARDEVENTDATE, MIN(CARDEVENTTIME) AS INTIME, MAX(CARDEVENTTIME) AS OUTTIME
FROM (SELECT T_PERSON.CARDNO, T_PERSON.NAME, T_TITLE.TITLENAME, T_CARDEVENT.CARDEVENTDATE, T_CARDEVENT.CARDEVENTTIME
FROM T_TITLE
INNER JOIN T_PERSON ON T_TITLE.TITLECODE = T_PERSON.TITLECODE
INNER JOIN T_CARDEVENT ON T_PERSON.PERSONID = T_CARDEVENT.PERSONID
ORDER BY T_PERSON.TITLECODE) GROUP BY CARDNO, NAME, TITLENAME, CARDEVENTDATE
And then the query would be:
select v1.CARDNO, v1.NAME, v1.TITLENAME, v1.CARDEVENTDATE, v1.INTIME, v1.OUTTIME,
case
when (v1.NAME = v1.TITLENAME) then v2.CARDEVENTDATE -- Replace v1.NAME = v1.TITLENAME with your reqd condn
else null end as LASTDATE,
case
when (v1.NAME = v1.TITLENAME) then v2.OUTTIME -- Replace v1.NAME = v1.TITLENAME with your reqd condn
else null end as LASTTIME
from myview v1
left outer join myview v2
on v2.CARDNO = (select max(CARDNO) from table1 where CARDNO < v1.CARDNO)
The v1.NAME = v1.TITLENAME in case stmt needs to be replaced with appropriate condn. I was not sure of the condn as its not mentioned in the question.

When you are designing your database you should consider the fact that you cannot rely on all the rows being in the right order. Instead you should create an identity value, that increment by one for every new row. And if you do this your solution becomes easy (or easier at least)
Assuming a new column called ID
SELECT colum1 FROM myTable WHERE ID = (SELECT ID FROM myTAble WHERE Column1 = Column2) - 1
If you get no match you will end up with ID -1 and this does not exist so you're ok.
If it is possible to get more than one match you will have to consider that too

Your table isn't in first normal form (1NF):
According to Date's definition of 1NF,
a table is in 1NF if and only if it is
'isomorphic to some relation', which
means, specifically, that it satisfies
the following five conditions:
1) There's no top-to-bottom ordering to the rows.
2) There's no left-to-right ordering to the columns.
3) ...

Related

Compare row with other rows in the same table in sql server

I have the below records in my table,
If the HoleNumber combination is not having 'A' and 'B' for the particular datetime, we need to remove the alphabets from the number.
i.e., Remove 'A' from third record and sixth record. Because, it doesn't have B combinations for that datetime.
delete from myTable
where id in
(
select id from myTable t1
inner join
(
select [date], left([holeNumber], len(holeNumber)-1) as hNumber
from myTable
group by [date], left([holeNumber], len(holeNumber)-1)
having count(holeNumber) = 1
) tmp
on t1.[date] = tmp.[date] and left(t1.holeNumber, len(holeNumber)-1) = tmp.hNumber);
would do it, provided your requirements are strictly to remove having only 1 type of holeNumber.
DBFiddle demo

SQL - Get Records within Date Range using 2 tables (Date Range/Hours given)

I have 2 tables:
Table 1:
Name, StartDate, EndDate
Ex:
Timmy, 9/12/17 08:00:00, 9/13/17 00:00:00
Timmy, 9/13/17 05:00:00, 9/13/17 07:00:00
Table 2:
Name, StartHour, Data...
Ex:
Timmy, 9/13/17 06:00:00, Data1...
Timmy, 9/13/17 04:00:00, Data2...
Timmy, 9/13/17 07:00:00, Data3...
Timmy, 9/12/17 14:00:00, Data4...
So, I need to get every record in Table 2 where that start hour is NOT inside of a date range in Table 1. This needs to be done for every name (so there can be multiple matching names in T1/T2 (see T2's data columns are different). It should be inclusive on the left side, exclusive on the right side.
So for this query, I want to see
Timmy, 9/13/17 04:00:00, Data2...
Timmy, 9/13/17 07:00:00, Data3... (Inclusive on end date)
I don't mind if its joined; I can just remove extra columns. I don't want to see duplicates though. I also keep hitting problems where I'll check if NOT (StartHour >= StartDate AND StartHour < EndDate). So each row/startHour in Table 2 needs to be checked against every row with a matching name in Table 1. I can't deal with that; I think it needs a subquery, but I don't know.
Checking if it is inside the ranges, but then negate because I don't want them if they are inside the range (inclusive,exclusive).
My solution attempt was:
SELECT *
FROM T1 LEFT JOIN T2
ON T1.Name = T2.Name
AND NOT (T2.StartHour >= T1.StartDate AND T2.StartHour < T2.EndDate)
Then just grab where there are no nulls.
That conditional can evaluate to true where in the row from T2 hits false for T1 row 1, but T1 row 2, 3, 4,... it is actually true, so I get 4 results back or whatever. Or it just doesn't evaluate it correctly because It doesn't look at all rows in T1.
For every entry of table2 matching with table1 you can calculate a count of how many times the condition is violated and if it is violated even once, you don't want that in the output. This is done by using a SUM(CASE WHEN..) in the below query.
SELECT T2.NAME, T2.STARTHOUR, T2.DATA
FROM
TABLE1 T1
INNER JOIN
TABLE2 T2
ON T1.NAME = T2.NAME
GROUP BY T2.NAME, T2.STARTHOUR, T2.DATA
HAVING SUM(CASE WHEN T2.STARTHOUR >= T1.STARTDATE AND T2.STARTHOUR < T1.STARTDATE THEN 1 ELSE 0 END) = 0;
As per exclusion and inclusion rules, you can see that the rule is not violated if table2's starthour is same as table1's enddate.
You can use this query.
SELECT DISTINCT T2.*
FROM Table2 T2
WHERE
NOT EXISTS (SELECT * FROM Table1 T1 WHERE
T1.Name = T2.Name
AND T2.StartHour > T1.StartDate
AND T2.StartHour < T1.EndDate )

SQL Server : return value in specific table2 column based on value in table1

I have a query that gets data from 2 tables.
Transaction table contains week_id, customer_id, upc12, sales_dollars
Products table contains upc12, column_1, column_2, column_3
I want my query to return the value in products table, based on what the customer_id is in the transaction table. customer_id = 1 should return column_1, customer_id = 2 should return column_3, etc.
SELECT
t.week_id,
customer_id,
upc12,
p.___________ sum(t.sales_dollars)
FROM
transaction t, products p
WHERE
t.upc_12 = p.upc_12
GROUP BY
t.week_id, customer_id, upc12, p.___________
Sorry if this makes no sense, but my research hasn't been very good, as I don't know how to correctly formulate my question. You probably guessed I'm new to SQL.
Thanks!
Here is one way to do it:
;WITH cte as
(
SELECT
t.week_id,
customer_id,
upc12,
CASE customer_id
WHEN 1 THEN p.Column_1
WHEN 2 THEN p.Column_2
WHEN 3 THEN p.Column_3
END As ColByCustomer,
t.sales_dollars
FROM transaction t
INNER JOIN products p on t.upc_12 = p.upc_12
)
SELECT week_id, customer_id, upc12, ColByCustomer, SUM(sales_dollars)
FROM cte
GROUP BY week_id, customer_id, upc12, ColByCustomer

SQL Pulling the latest information and information from another table

I have a record table that is recording changes within a table. I can pull the data from the first table fine, however when i try to join in another table to add some of its column information it stops displaying the information.
PartNumber | PartDesc | value | date
1 | test | 1 | 3/4/2015
I wanted to include the Aisle tag's from the location table
PartNumber| AisleTag | AisleTagTwo
1 | A1 | N/A
here is what i have as my sql statement so far
Select t1.PartNumber, t1.PartDesc , t1.NewValue , t1.Date,t2.AisleTag,t2.AisleTagTwo
from InvRecord t1
JOIN PartAisleListTbl t2 ON t1.PartNumber = t2.PartNumber
where Date = (select max(Date) from InvRecord where t1.PartNumber = InvRecord.PartNumber)
order by t1.PartNumber
it is coming up blank, my original sql statement doesn't include anything from t2. I am not sure what approach to go with in terms of getting the data combined any help is much appreciated thank you !
this should be the end result
PartNumber | PartDesc | value | date | AisleTag | AisleTagTwo
1 | test | 1 | 3/4/2015 | A1 | N/A
Pull the most recent row (based on Date) for each PartNumber in Table A and append data from Table B (joined on PartNumber):
SELECT *
FROM (
SELECT A.PartNumber
, A.PartDesc
, A.NewValue
, A.Date
, B.AisleTag
, B.AisleTagTwo
, DateSeq = ROW_NUMBER() OVER(PARTITION BY A.PartNumber ORDER BY A.Date DESC)
FROM InvRecord A
LEFT JOIN PartAisleListTbl B
ON A.PartNumber = B.PartNumber
) A
WHERE A.DateSeq = 1
ORDER BY A.PartNumber
Are you returning no records at all, or only records with AisleTag and AisleTagTwo as null?
Your sentence "it is coming up blank, my original sql statement doesn't include anything from t2." makes it sound like you're getting records with nulls for the t2 fields.
If you are, then you probably have a record in t2 that has nulls for those fields.
For troubleshooting purposes, try running the query without the WHERE clause:
Select t1.PartNumber, t1.PartDesc , t1.NewValue , t1.Date,t2.AisleTag,t2.AisleTagTwo
from InvRecord t1
JOIN PartAisleListTbl t2 ON t1.PartNumber = t2.PartNumber
order by t1.PartNumber
If you do get records, your problem is with the WHERE clause. If you don't, your problem is with the PartNumber fields in InvRecord and PartAisleListTbl not matching.
Not sure why your's isn't working... is date in both t1 and t2 by any chance?
Here's it re factored to use a inline view instead of a correlated query wonder if it makes a difference.
Select t1.PartNumber, t1.PartDesc , t1.NewValue , t1.Date,t2.AisleTag,t2.AisleTagTwo
from InvRecord t1
JOIN PartAisleListTbl t2
ON t1.PartNumber = t2.PartNumber
JOIN (select max(Date) mdate, PartNumber from InvRecord GROUP BY PartNumber) t3
on t3.partNumber= T1.PartNumber
and T3.mdate = T1.Date
order by t1.PartNumber

Query to collect data from previous rows

I have a table with records as, in example data below a CO.Nr are TH-123,Th-456 and so on... I need to collect the data..
Nr. CO.Nr Employee Resp Description Date
1 TH-123 ABC NULL HELLO 10.05.2010
2 TH-123 NULL S14 NULL 18.05.2010
3 TH-123 DEF NULL 13.05.2010
4 TH-456 XYZ NULL NULL 1.07.2010
5 TH-456 NULL S19 SOME NULL
6 TH-456 TEXT 08.05.2010
7 TH-456 NULL 28.05.2010
For TH-123,
If Nr. is maximum, that is the record i need to start with group by CO.Nr, so it is the record with Nr as 3,
if the value in the other columns is NULL or space, go to a record above that is the record with Nr as 2, even if it has null value go to a record above that record with Nr. as 1 in this case.
In the 3 records i need to take the maximum of date.
For the above data, i need to have output as,
CO.Nr Employee Resp Description Date
TH-123 DEF S14 HELLO 18.05.2010
TH-456 XYZ S19 TEXT 01.07.2010
Thanks in advance!
You can do it many ways
select [co.nr],
(select top(1) employee from mytable b where b.[co.nr]=a.[co.nr] and
employee is not null order by nr desc) as employee,
(select top(1) resp from mytable b where b.[co.nr]=a.[co.nr] and
resp is not null order by nr desc) as resp,
(select top(1) description from mytable b where b.[co.nr]=a.[co.nr] and
description is not null order by nr desc) as description,
(select max([date]) from mytable b where b.[co.nr]=a.[co.nr]) as Date
from (
select distinct [co.nr]
from mytable ) as a
You can use a subselect to choose the record you want, then join on that. Something like the following for the employees one (I'll leave the rest of the columns as an exercise):
SELECT MyTable.[CO.Nr], Employees.Employee
FROM MyTable
LEFT OUTER JOIN (SELECT FIRST(Employee) as Employee, [CO.Nr]
FROM MyTable
WHERE Employee IS NOT NULL AND Employee <> ''
GROUP BY [CO.Nr]
ORDER BY [Nr.] DESC) Employees
ON MyTable.[CO.Nr] = Employees.[CO.Nr]
GROUP BY MyTable.[CO.Nr]
Or, if FIRST() is not a valid aggregate function, as mentioned in your comments, you can try subselects in your SELECT clause, like:
SELECT t.MyTable.[CO.Nr],
(SELECT TOP(1) x.Employee
FROM MyTable x
WHERE x.[CO.Nr] = t.[CO.Nr]
AND x.Employee IS NOT NULL AND x.Employee <> ''
ORDER BY [Nr.] DESC) as Employee
FROM MyTable t
GROUP BY t.[CO.Nr]

Resources