I'm fairly new to SQL and tried solving this problem for about two days now, to no avail.
The question is, how can I update values in table Table_1 from values in Table_2, considering only specific subset of rows in Table_2, and without using cursors if possible.
More specifically, I have these two tables:
CREATE TABLE [dbo].[Table_1](
[ID] [int] NOT NULL,
[LastAmount] [int] NOT NULL,
[LastDate] [datetime] NOT NULL
) ON [PRIMARY];
CREATE TABLE [dbo].[Table_2](
[ID] [int] NOT NULL,
[Amount] [int] NOT NULL,
[Date_] [datetime] NOT NULL
) ON [PRIMARY];
In the tables there are following values:
INSERT INTO [dbo].[Table_1]
VALUES (1, 0, CONVERT(DATETIME, '19000101', 112)),
(2, 0, CONVERT(DATETIME, '19000101', 112));
INSERT INTO [dbo].[Table_2]
VALUES (1, 10, CONVERT(DATETIME, '19750101', 112)),
(1, 20, CONVERT(DATETIME, '19500101', 112)),
(1, 15, CONVERT(DATETIME, '20000101', 112)),
(2, 30, CONVERT(DATETIME, '20100101', 112));
The point is to update values in Table_1 where ID matches Table_2.
Table_1.LastAmount should get Table_2.Amount with the most recent Table_2.Date_. Similarly for Table_1.LastDate it should get Table_2.Date_ where the date is the most recent for that specific ID.
So, Table_1 before update:
ID |LastAmount |LastDate
----|-----------|--------
1 |0 |1900-01-01 00:00:00.0000
2 |0 |1900-01-01 00:00:00.0000
Table_2:
ID |Amount |Date
----|-----------|--------
1 |10 |1975-01-01 00:00:00.0000
1 |20 |1950-01-01 00:00:00.0000
1 |15 |2000-01-01 00:00:00.0000
2 |30 |2010-01-01 00:00:00.0000
Table_1 after update:
ID |LastAmount |LastDate
----|-----------|--------
1 |15 |2000-01-01 00:00:00.0000
2 |30 |2010-01-01 00:00:00.0000
I tried all kinds of UPDATE with INNER JOIN, or using an inline SELECT when assigning the value, but none of them worked. Many thanks in advance.
An update from is useful in this situation. row_number() is used here with the source table to determine the most recent entry in Table_2.
update
Table_1
set
LastAmount = T2.Amount
,LastDate = T2.Date_
from
(
select
ID
,Amount
,Date_
,row_number() over (partition by ID order by Date_ desc) as RowNumber
from
Table_2
) T2
where
Table_1.ID = T2.ID
and T2.RowNumber = 1
Do like this:
Update Table_1
Set LastAmount = Table_2.Amount,
LastDate = Table_2.[Date_]
from (SELECT ID, MAX([Date_]) as MaxDate FROM TABLE_2 GROUP BY ID) AS Max_Table2
inner join Table_2 on Max_Table2.MaxDate = Table_2.[Date_] and Max_Table2.id = Table_2.id
inner join table_1 on table_1.id = Table_2.id
Basically you have filter the table2 to get the max date and join everything up to find the lastdate and amount.
It's a simple use of ROW_NUMBER() and a CTE to do this:
;With Ordered as (
select ID,Amount,Date_,
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Date_ DESC) rn
from Table_2
)
update t1
set LastAmount = o.Amount,
LastDate = o.Date_
from
Table_1 t1
inner join
Ordered o
on
t1.ID = o.ID and
o.rn = 1
(You could write it as a subquery rather than a CTE, but I picked a CTE in this example)
Related
I have one doubt in sql server
get records based on installments
Table :productdetails
CREATE TABLE [dbo].[productdetails](
[productid] [int] NULL,
[Productrstartdate] [date] NULL,
[Productenddate] [date] NULL,
[EMIInstallment] [int] NULL
) ON [PRIMARY]
GO
INSERT [dbo].[productdetails] ([productid], [Productrstartdate], [Productenddate], [EMIInstallment]) VALUES (1, CAST(N'2020-10-02' AS Date), CAST(N'2024-10-02' AS Date), 5)
GO
INSERT [dbo].[productdetails] ([productid], [Productrstartdate], [Productenddate], [EMIInstallment]) VALUES (2, CAST(N'2020-02-10' AS Date), CAST(N'2021-02-10' AS Date), 2)
GO
INSERT [dbo].[productdetails] ([productid], [Productrstartdate], [Productenddate], [EMIInstallment]) VALUES (3, CAST(N'2019-01-10' AS Date), CAST(N'2019-01-10' AS Date), 1)
GO
INSERT [dbo].[productdetails] ([productid], [Productrstartdate], [Productenddate], [EMIInstallment]) VALUES (4, CAST(N'2019-01-18' AS Date), CAST(N'2021-01-18' AS Date), 3)
GO
based on above data i want output like below
Productid |Installmentdate |noofinstallmentcount
1 |2020-10-02 |1
1 |2021-10-02 |2
1 |2022-10-02 |3
1 |2023-10-02 |4
1 |2024-10-02 |5
2 |2020-02-10 |1
2 |2021-02-10 |2
3 |2019-01-10 |1
4 |2019-01-18 |1
4 |2020-01-18 |2
4 |2021-01-18 |3
i tried like below :
DECLARE #MINDATE DATE='2019-01-18'
DECLARE #COUNT INT=10
dECLARE #MAXDATE DATE='2024-10-02'
;WITH ABC
AS
(
SELECT productid ,#MINDATE CalendarDate ,1 as id from [dbo].[productdetails]
UNION ALL
SELECT a.productid ,DATEADD(YEAR,1,a.Productrstartdate ), 1 FROM [dbo].[productdetails] a
join [dbo].[productdetails] b on a.productid=b.productid
WHERE #MINDATE <#MAXDATE )
SELECT * FROM ABC
above query not given expected output
could you please tell me how to write query to achive this task in sql server .
You want a tally here. If you're not going to have a value (much) higher than 10, then just a VALUES clause will work:
SELECT pd.productid,
DATEADD(YEAR, V.I, pd.Productrstartdate) AS Installmentdate,
V.I + 1 AS noofinstallmentcount
FROM dbo.productdetails pd
JOIN (VALUES(0),(1),(2),(3),(4),(5),(6),(7),(8),(9))V(I) ON pd.EMIInstallment > V.I;
If you need bigger numbers, just use a bigger tally:
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
FROM N N1, N N2, N N3) --1000 rows
SELECT pd.productid,
DATEADD(YEAR, T.I, pd.Productrstartdate) AS Installmentdate,
T.I + 1 AS noofinstallmentcount
FROM dbo.productdetails pd
JOIN Tally T ON pd.EMIInstallment > T.I;
You could create a temp table that mimics the actual productdetails table, then iterate through it, creating an output table that lists the product id with each installment date. Once you have that, you can use ROW_NUMBER() to count the installment numbers. Try this:
SELECT *
INTO #productdetails
FROM productdetails
CREATE TABLE #output (
productid int null
,installmentdate date null)
WHILE (SELECT COUNT(*) FROM #productdetails) > 0
BEGIN
DECLARE #yr int = 0
WHILE (SELECT TOP 1 DATEDIFF(year, DATEADD(year, #yr, Productrstartdate), productenddate) FROM #productdetails) >= 0
BEGIN
INSERT INTO #output (
productid
,installmentdate)
SELECT top 1
productid
,DATEADD(year, #yr, Productrstartdate) installmentdate
FROM #productdetails
SET #yr = #yr + 1
END
DELETE TOP (1) FROM #productdetails
END
SELECT *
,ROW_NUMBER() OVER (PARTITION BY ProductId ORDER BY InstallmentDate asc) NumberOfInstallmentCount
FROM #output
DROP TABLE #output, #productdetails
My table structure as below
Category Sex Last Modified Date Id
7 2 2015-01-16 87603
7 1 2014-11-27 87729
7 2 2018-09-06 87135
7 1 2017-12-27 87568
My sql query as below
SELECT
MAX(Id) AS Id
FROM
Table
GROUP BY
Category, Sex
Result as below
87603
87729
But I would like to get Id as Max Last Modified Date. Correct result should be as below
87135
87568
You can use ROW_NUMBER() to find most recent row per group:
SELECT Id, LastModifiedDate
FROM (
SELECT Id, LastModifiedDate, ROW_NUMBER() OVER (PARTITION BY Category, Sex ORDER BY LastModifiedDate DESC) AS rnk
FROM t
) AS cte
WHERE rnk = 1
Use RANK() if you're interested in finding all rows with ties for LastModifiedDate.
You can also get it as
SELECT T.*
FROM
(
SELECT Sex,
MAX([Last Modified Date]) [Last Modified Date],
Category
FROM T
GROUP BY Sex,
Category
) TT INNER JOIN T ON T.[Last Modified Date] = TT.[Last Modified Date]
WHERE T.Sex = TT.Sex
AND
T.Category = TT.Category;
Returns:
+----------+-----+---------------------+-------+
| Category | Sex | Last Modified Date | Id |
+----------+-----+---------------------+-------+
| 7 | 2 | 06/09/2018 00:00:00 | 87135 |
| 7 | 1 | 27/12/2017 00:00:00 | 87568 |
+----------+-----+---------------------+-------+
We can get the solution by joining the same table with its grouped set:
SELECT MIN(T.Id)
FROM Table T
INNER JOIN (SELECT Category,
Sex,
MAX(LastModifiedDate) AS LastModifiedDate
FROM Table
GROUP BY Category, Sex) GT
ON GT.Category = T.Category
AND GT.Sex = T.Sex
AND GT.LastModifiedDate = T.LastModifiedDate
GROUP BY T.Category, T.Sex
Other option is to use correlated subquery :
select t.*
from table t
where t.LastModifiedDate = (select max(t1.LastModifiedDate)
from table t1
where t1.Category = t.Category and t1.Sex = t.Sex
);
Here are a few different approaches... (in no particular order)
IF OBJECT_ID('tempdb..#TestData', 'U') IS NOT NULL
DROP TABLE #TestData;
GO
CREATE TABLE #TestData (
Category TINYINT NOT NULL,
Sex TINYINT NOT NULL,
LastModifiedDate DATE NOT NULL,
Id INT NOT NULL
);
GO
INSERT #TestData(Category, Sex, LastModifiedDate, Id) VALUES
(7, 2, '2015-01-16', 87603),
(7, 1, '2014-11-27', 87729),
(7, 2, '2018-09-06', 87135),
(7, 1, '2017-12-27', 87568);
GO
/* nonclustered index to support the query. */
CREATE UNIQUE NONCLUSTERED INDEX ix_TestData_Category_Sex_LastModifiedDate
ON #TestData (Category ASC, Sex ASC, LastModifiedDate DESC)
INCLUDE (Id);
GO
--====================================================
-- option 1: TOP(n) WITH TIES...
SELECT TOP (1) WITH TIES
td.Id
FROM
#TestData td
ORDER BY
ROW_NUMBER() OVER (PARTITION BY td.Category, td.Sex ORDER BY td.LastModifiedDate DESC);
GO
-----------------------------------------------------
-- option 2: Filter on ROW_NUMBER()...
WITH
cte_AddRN AS (
SELECT
td.Id,
rn = ROW_NUMBER() OVER (PARTITION BY td.Category, td.Sex ORDER BY td.LastModifiedDate DESC)
FROM
#TestData td
)
SELECT
arn.Id
FROM
cte_AddRN arn
WHERE
arn.rn = 1;
GO
-----------------------------------------------------
-- option 3: binary concatination...
SELECT
Id = CONVERT(INT, SUBSTRING(MAX(bv.bin_val), 4, 4))
FROM
#TestData td
CROSS APPLY ( VALUES (CONVERT(BINARY(3), td.LastModifiedDate) + CONVERT(BINARY(4), td.Id)) ) bv (bin_val)
GROUP BY
td.Category,
td.Sex;
GO
--====================================================
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
The query that I've build does not fit the solution. I've tried many queries but can't get the result I want.
I have the following table
CREATE TABLE [dbo].[test](
[ID] [int] IDENTITY(1,1) NOT NULL,
[ATC] [varchar](15) NOT NULL,
[PID] [varchar](7) NOT NULL,
[NAME] [varchar](50) NOT NULL,
[REG_DATE] [datetime] NULL,
[ACTIVE] [bit] NOT NULL CONSTRAINT [DF_test_ACTIVE] DEFAULT ((1))
) ON [PRIMARY]
Example data
INSERT INTO [dbo].[test] ([ATC],[PID],[NAME],[REG_DATE],[ACTIVE])
VALUES ('A01','123456','TEST1','2016-08-31 00:00:00.000',0);
INSERT INTO [dbo].[test] ([ATC],[PID],[NAME],[REG_DATE],[ACTIVE])
VALUES ('A01','123456','TEST2','2016-09-01 00:00:00.000',0);
INSERT INTO [dbo].[test] ([ATC],[PID],[NAME],[REG_DATE],[ACTIVE])
VALUES ('A01','123456','TEST3','2016-09-02 00:00:00.000',0);
INSERT INTO [dbo].[test] ([ATC],[PID],[NAME],[REG_DATE],[ACTIVE])
VALUES ('A01','123456','TEST4','2016-09-03 00:00:00.000',0);
INSERT INTO [dbo].[test] ([ATC],[PID],[NAME],[REG_DATE],[ACTIVE])
VALUES('A01','123456','TEST5','2016-09-06 00:00:00.000',1);
Example Query:
;WITH CTE AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY ATC, PID ORDER BY REG_DATE ASC) AS ROWNUM,* FROM [dbo].[test]
WHERE ACTIVE=0
)
SELECT DATEDIFF(DAY, d2.REG_DATE, d1.REG_DATE),d1.NAME, d1.REG_DATE AS ACTIVE_REC_DATE, d2.REG_DATE AS NOTACTIVE_REC_DATE, d1.ACTIVE, d2.ACTIVE FROM [dbo].[test] as d1
LEFT JOIN CTE d2 ON d2.ATC = d1.ATC AND d2.PID = d1.PID
AND DATEDIFF(DAY, d2.REG_DATE, d1.REG_DATE) <= 7
WHERE d1.ACTIVE=1 AND d1.PID=123456;
Wanted result:
The record with column ACTIVE True (1) should contain (if the record exists) the REG_DATE of the not active previous record max 7 days old. Like:
(No column name) NAME ACTIVE_REC_DATE NOTACTIVE_REC_DATE ACTIVE ACTIVE
3 TEST5 2016-09-06 00:00:00.000 2016-08-31 00:00:00.000 1 0
Currently the query result contains multiple records because the are more records that will fall in the 7 days period. I need to join 1 record that will be the max 7 day old one.
I've used the ROW_NUMBER() with over partition by so I can use and identify the first record because I will be sorting ascending. This doesn't work when there is no previous records available or the previous records are older then 7 days
When there is no records to join is ignored can use INNER JOIN or date columns at null
I hope I'm clear with my explanation.
SELECT DATEDIFF(DAY, d2.REG_DATE, d1.REG_DATE),d1.NAME, d1.REG_DATE AS ACTIVE_REC_DATE, d2.REG_DATE AS NOTACTIVE_REC_DATE, d1.ACTIVE, d2.ACTIVE FROM [dbo].[test] as d1
OUTER APPLY
(SELECT TOP 1 T1.* FROM dbo.test t1 WHERE t1.ATC = d1.ATC AND t1.PID = d1.PID and DATEDIFF(DAY, t1.REG_DATE, d1.REG_DATE) <= 7 order by t1.REG_DATE desc) d2
WHERE d1.ACTIVE=1 AND d1.PID=123456;
You can return a single row for a PID by adding a filter on ROWNUM to your left join:
;WITH CTE AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY ATC, PID ORDER BY REG_DATE ASC) AS ROWNUM,* FROM [dbo].[test]
WHERE ACTIVE=0
)
SELECT DATEDIFF(DAY, d2.REG_DATE, d1.REG_DATE),d1.NAME, d1.REG_DATE AS ACTIVE_REC_DATE, d2.REG_DATE AS NOTACTIVE_REC_DATE, d1.ACTIVE, d2.ACTIVE FROM [dbo].[test] as d1
LEFT JOIN CTE d2 ON d2.ATC = d1.ATC AND d2.PID = d1.PID
AND DATEDIFF(DAY, d2.REG_DATE, d1.REG_DATE) <= 7
AND d2.ROWNUM = 1
WHERE d1.ACTIVE=1 AND d1.PID=123456;
It's not clear from the question how the query should behave when no previous records from the last seven days exist.
I have a table containing orders. I would like to select those orders that are a certain number of days apart for a specific client. For example, in the table below I would like to select all of the orders for CustomerID = 10 that are at least 30 days apart from the previous instance. With the starting point to be the first occurrence (07/05/2014 in this data).
OrderID | CustomerID | OrderDate
==========================================
1 10 07/05/2014
2 10 07/15/2014
3 11 07/20/2014
4 11 08/20/2014
5 11 09/21/2014
6 10 09/23/2014
7 10 10/15/2014
8 10 10/30/2014
I would want to select OrderIDs (1,6,8) since they are 30 days apart from each other and all from CustomerID = 10. OrderIDs 2 and 7 would not be included as they are within 30 days of the previous order for that customer.
What confuses me is how to set the "checkpoint" to the last valid date. Here is a little "pseudo" SQL.
SELECT OrderID
FROM Orders
WHERE CusomerID = 10
AND OrderDate > LastValidOrderDate + 30
i came here and i saw #SveinFidjestøl already posted answer but i can't control my self after by long tried :
with the help of LAG and LEAD we can comparison between same column
and as per your Q you are looking 1,6,8. might be this is helpful
SQL SERVER 2012 and after
declare #temp table
(orderid int,
customerid int,
orderDate date
);
insert into #temp values (1, 10, '07/05/2014')
insert into #temp values (2, 10, '07/15/2014')
insert into #temp values (3, 11, '07/20/2014')
insert into #temp values (4, 11, '08/20/2014')
insert into #temp values (5, 11, '09/21/2014')
insert into #temp values (6, 10, '09/23/2014')
insert into #temp values (7, 10, '10/15/2014')
insert into #temp values (8, 10, '10/30/2014');
with cte as
(SELECT orderid,customerid,orderDate,
LAG(orderDate) OVER (ORDER BY orderid ) PreviousValue,
LEAD(orderDate) OVER (ORDER BY orderid) NextValue,
rownum = ROW_NUMBER() OVER (ORDER BY orderid)
FROM #temp
WHERE customerid = 10)
select orderid,customerid,orderDate from cte
where DATEDIFF ( day , PreviousValue , orderDate) > 30
or PreviousValue is null or NextValue is null
SQL SERVER 2005 and after
WITH CTE AS (
SELECT
rownum = ROW_NUMBER() OVER (ORDER BY p.orderid),
p.orderid,
p.customerid,
p.orderDate
FROM #temp p
where p.customerid = 10)
SELECT CTE.orderid,CTE.customerid,CTE.orderDate,
prev.orderDate PreviousValue,
nex.orderDate NextValue
FROM CTE
LEFT JOIN CTE prev ON prev.rownum = CTE.rownum - 1
LEFT JOIN CTE nex ON nex.rownum = CTE.rownum + 1
where CTE.customerid = 10
and
DATEDIFF ( day , prev.orderDate , CTE.orderDate) > 30
or prev.orderDate is null or nex.orderDate is null
GO
You can use the LAG() function, available in SQL Server 2012, together with a Common Table Expression. You calculate the days between the customer's current order and the customer's previous order and then query the Common Table Expression using the filter >= 30
with cte as
(select OrderId
,CustomerId
,datediff(d
,lag(orderdate) over (partition by CustomerId order by OrderDate)
,OrderDate) DaysSinceLastOrder
from Orders)
select OrderId, CustomerId, DaysSinceLastOrder
from cte
where DaysSinceLastOrder >= 30 or DaysSinceLastOrder is null
Results:
OrderId CustomerId DaysSinceLastOrder
1 10 NULL
6 10 70
3 11 NULL
4 11 31
5 11 32
(Note that 1970-01-01 is chosen arbitrarily, you may choose any date)
Update
A slighty more reliable way of doing it will involve a temporary table. But the original table tbl can be left unchanged. See here:
CREATE TABLE #tmp (id int); -- set-up temp table
INSERT INTO #tmp VALUES (1); -- plant "seed": first oid
WHILE (##ROWCOUNT>0)
INSERT INTO #tmp (id)
SELECT TOP 1 OrderId FROM tbl
WHERE OrderId>0 AND CustomerId=10
AND OrderDate>(SELECT max(OrderDate)+30 FROM tbl INNER JOIN #tmp ON id=OrderId)
ORDER BY OrderDate;
-- now list all found entries of tbl:
SELECT * FROM tbl WHERE EXISTS (SELECT 1 FROM #tmp WHERE id=OrderId)
#tinka shows how to use CTEs to do the trick, and the new windowed functions (for 2012 and later) are probably the best answer. There is also the option, assuming you do not have a very large data set, to use a recursive CTE.
Example:
declare #customerid int = 10;
declare #temp table
(orderid int,
customerid int,
orderDate date
);
insert into #temp values (1, 10, '07/05/2014')
insert into #temp values (2, 10, '07/15/2014')
insert into #temp values (3, 11, '07/20/2014')
insert into #temp values (4, 11, '08/20/2014')
insert into #temp values (5, 11, '09/21/2014')
insert into #temp values (6, 10, '09/23/2014')
insert into #temp values (7, 10, '10/15/2014')
insert into #temp values (8, 10, '10/30/2014');
with datefilter AS
(
SELECT row_number() OVER(PARTITION BY CustomerId ORDER BY OrderDate) as RowId,
OrderId,
CustomerId,
OrderDate,
DATEADD(day, 30, OrderDate) as FilterDate
from #temp
WHERE CustomerId = #customerid
)
, firstdate as
(
SELECT RowId, OrderId, CustomerId, OrderDate, FilterDate
FROM datefilter
WHERE rowId = 1
union all
SELECT datefilter.RowId, datefilter.OrderId, datefilter.CustomerId,
datefilter.OrderDate, datefilter.FilterDate
FROM datefilter
join firstdate
on datefilter.CustomerId = firstdate.CustomerId
and datefilter.OrderDate > firstdate.FilterDate
WHERE NOT EXISTS
(
SELECT 1 FROM datefilter betweens
WHERE betweens.CustomerId = firstdate.CustomerId
AND betweens.orderdate > firstdate.FilterDate
AND datefilter.orderdate > betweens.orderdate
)
)
SELECT * FROM firstdate