sql developer how to filter date - sql

Peace
I have a table full of values and I need to filter all the dates of each month 10
That is to delete everyone who is between 10-01-2022 TO 10-31-2022
And not a specific date as I presented
create table content(
cname varchar2(1),
type varchar2(15),
episodes number,
country varchar2(15),
language varchar2(15),
releasedate date,
primary key(cname, type));
insert into content values('A','film', 1, 'China', 'Mandarin', '03/10/2022');
insert into content values('B','film', 1, 'Taiwan', 'Cantonese', '30/10/2022');
insert into content values('C','film', 1, 'Singapore', 'Malay', '15/09/2022');
insert into content values('A','series', 8, 'Korea', 'Korean', '28/09/2022');
insert into content values('B','series', 10, 'China', 'Mandarin', '03/10/2022');
insert into content values('C','series', 18, 'Korea', 'Korean', '01/11/2022');
insert into content values('D','series', 8, 'Korea', 'Korean', '16/09/2022');
insert into content values('D','documentary', 3, 'China', 'Mandarin', '18/10/2022');
insert into content values('E','documentary', 6, 'Taiwan', 'Mandarin', '17/10/2022');
SELECT cname,type,country,episodes,language,releasedate
FROM content
minus
SELECT cname,type,country,episodes,language,releasedate
FROM content
WHERE content.country ='China'
AND
content.TYPE ='documentary'
AND
content.MONTH(releasedate) =10;

If is intended to fetch all data of October without checking the year, we can use EXTRACT, see here the documentation
SELECT cname, type, country, episodes, language, releasedate
FROM content
WHERE EXTRACT(MONTH FROM releasedate) = 10;
Otherwise, if only the October 2022 should be considered, we will prefer to use BETWEEN rather than two times EXTRACT for both year and month.
SELECT cname, type, country, episodes, language, releasedate
FROM content
WHERE releasedate BETWEEN
TO_DATE('2022-10-01','YYYY-MM-DD') AND
TO_DATE('2022-10-31','YYYY-MM-DD');
If your dates can contain a time, we should add a TRUNC to avoid a date like '10/31/2022 12:22:22' will not be found:
SELECT cname, type, country, episodes, language, releasedate
FROM content
WHERE TRUNC(releasedate) BETWEEN
TO_DATE('2022-10-01','YYYY-MM-DD') AND
TO_DATE('2022-10-31','YYYY-MM-DD');
Here we can verify this is working correctly: db<>fiddle

Change from:
SELECT ...
MINUS
SELECT ... WHERE X AND Y AND Z
to a single query:
SELECT ...
WHERE NOT X OR NOT Y OR NOT Z
Which for your query would be:
SELECT *
FROM content
WHERE country != 'China'
OR type != 'documentary'
OR releasedate < DATE '2022-10-01'
OR releasedate >= DATE '2022-11-01';
or, if you can have NULL values:
SELECT *
FROM content
WHERE country != 'China'
OR country IS NULL
OR type != 'documentary'
OR type IS NULL
OR releasedate < DATE '2022-10-01'
OR releasedate >= DATE '2022-11-01'
OR releasedate IS NULL;
If you want to always exclude that month then use a mix of AND and OR:
SELECT *
FROM content
WHERE ( country != 'China'
OR type != 'documentary' )
AND ( releasedate < DATE '2022-10-01'
OR releasedate >= DATE '2022-11-01' );
fiddle

Related

Get userwise balance and first transaction date of users in SQL

I have created a Transaction table with columns card_id, amount, created_at. There may be more than 1 row of one user so I want to return the value card_id, sum(amount), first created_at date of all users.
CREATE TABLE Transactions(card_id int, amount money, created_at date)
INSERT INTO Transactions(card_id, amount, created_at)
SELECT 1, 500, '2016-01-01' union all
SELECT 1, 100, '2016-01-01' union all
SELECT 1, 100, '2016-01-01' union all
SELECT 1, 200, '2016-01-02' union all
SELECT 1, 300, '2016-01-03' union all
SELECT 2, 100, '2016-01-04' union all
SELECT 2, 200, '2016-01-05' union all
SELECT 3, 700, '2016-01-06' union all
SELECT 1, 100, '2016-01-07' union all
SELECT 2, 100, '2016-01-07' union all
SELECT 3, 100, '2016-01-07'
I have created function for that but one of my client says I need query not function. Can anyone here suggest what query to use?
CREATE FUNCTION [dbo].[card_id_data]()
RETURNS #t TABLE
(
card_id text,
amount money,
dateOfFirstTransaction date
)
AS
BEGIN
INSERT INTO #t(card_id)
SELECT DISTINCT(card_id) FROM Transactions;
UPDATE #t
SET dateOfFirstTransaction = b.createdat
FROM
(SELECT DISTINCT(card_id) cardid,
MIN(created_at) createdat
FROM Transactions
WHERE amount < 0
GROUP BY card_id) b
WHERE card_id = b.cardid;
UPDATE #t
SET amount = T.AMOUNT
FROM
(SELECT
card_id AS cardid, SUM(MIN(AMOUNT)) AMOUNT, created_at
FROM Transactions
WHERE amount < 0
GROUP BY card_id, created_at) T
WHERE card_id = cardid
AND dateOfFirstTransaction = created_at;
RETURN
END
I want a result as shown in this screenshot:
You can use DENSE_RANK for this. It will number the rows, taking into account tied places (same dates)
SELECT
t.card_id,
SumAmount = SUM(amount),
FirstDate = MIN(t.created_at)
FROM (
SELECT *,
rn = DENSE_RANK() OVER (PARTITION BY t.card_id ORDER BY t.created_at)
FROM dbo.Transactions t
) t
WHERE t.rn = 1
GROUP BY t.card_id;
If the dates are actually dates and times, and you want to sum the whole day, change t.created_at to CAST(t.created_at AS date)
Try this:
/*
CREATE TABLE dbo.Transactions
(
card_id INT,
amount MONEY,
created_at DATE
);
INSERT INTO dbo.Transactions (card_id, amount, created_at)
VALUES (1, 500, '2016-01-01'),
(1, 100, '2016-01-01'),
(1, 100, '2016-01-01'),
(1, 200, '2016-01-02'),
(1, 300, '2016-01-03'),
(2, 100, '2016-01-04'),
(2, 200, '2016-01-05'),
(3, 700, '2016-01-06'),
(1, 100, '2016-01-07'),
(2, 100, '2016-01-07'),
(3, 100, '2016-01-07');
*/
WITH FirstDatePerCard AS
(
SELECT
card_id,
FirstDate = MIN(created_at)
FROM
dbo.Transactions
GROUP BY
card_id
)
SELECT DISTINCT
t.card_id,
SumAmount = SUM(amount) OVER (PARTITION BY t.card_id),
FirstDate = f.FirstDate
FROM
FirstDatePerCard f
INNER JOIN
dbo.Transactions t ON f.card_id = t.card_id AND f.FirstDate = t.created_at
You'll get an output something like this:
card_id SumAmount FirstDate
--------------------------------
1 700.00 2016-01-01
2 100.00 2016-01-04
3 700.00 2016-01-06
Is that what you're looking for??
UPDATE: OK, so you want to sum the amount only for the first_date, for every card_id - is that correct? (wasn't clear from the original question)
Updated my solution accordingly

Match a row with a date that is between 2 dates in another table

I am writing a query that calculates whether the correct booking fee was charged for all bookings. The structure of the tables are below. Please note that due to the environment I am working in I cannot create any stored procedures or functions to help me.
BOOKINGS
Date date,
CustomerId int,
BookingTypeId int,
FeeCharged money
FEES
BookingTypeId int,
FeeAmount money,
EffectiveFrom date
Given the example data set below how do I query the data to ensure the fee charged per booking matches the correct fee in the fees table based on the effective from date:
try this
WITH
Fees (BookingTypeId, FeeAmount, EffectiveFrom) AS (
SELECT 1, 50, '2019-06-01'
UNION ALL SELECT 1, 55, '2019-09-01'
),
Bookings (Date, CustomerId, BookingTypeId, FeeCharged) AS (
SELECT '2019-07-01', 1, 1, 50
UNION ALL SELECT '2019-07-02', 1, 1, 50
UNION ALL SELECT '2019-10-01', 1, 1, 150
),
BookingFeeUpdate as (
SELECT
Bookings.BookingTypeId,
Bookings.Date,
MAX(EffectiveFrom) LastFeeUpdate
FROM
Bookings
LEFT JOIN Fees ON
Fees.BookingTypeId = Bookings.BookingTypeId
AND Fees.EffectiveFrom <= Bookings.Date
GROUP BY
Bookings.BookingTypeId,
Bookings.Date
)
SELECT
Bookings.*, Fees.FeeAmount as CorrectFee, Fees.EffectiveFrom, case Fees.FeeAmount when FeeCharged then 1 else 0 end Correct
FROM
Bookings
INNER JOIN BookingFeeUpdate ON
BookingFeeUpdate.BookingTypeId = Bookings.BookingTypeId
AND BookingFeeUpdate.Date = Bookings.Date
LEFT JOIN Fees ON
Fees.BookingTypeId = Bookings.BookingTypeId
AND Fees.EffectiveFrom = BookingFeeUpdate.LastFeeUpdate
--WHERE Fees.FeeAmount <> Bookings.FeeCharged

Msg 402, Level 16, State 1, Line 4 The data types varchar and varchar are incompatible in the subtract operator

I was writing the following code
SELECT
customer_Id,
DOB,
DATEDIFF(MONTH, CONVERT(date, Customer.DOB, 103), GETDATE()) AS [Age IN Months],
Gender,
city_code,
Qty,
(total_amt - (Rate + Tax)) AS [Total_sale_amt]
FROM
Customer
JOIN
Transactions ON Customer.customer_Id = Transactions.cust_id
ORDER BY
[Age IN Months] DESC;
Ended up with following error msg
Msg 402, Level 16, State 1, Line 4
The data types varchar and varchar are incompatible in the subtract operator.
Please let me know as in this section `
( total_amt - ( Rate + Tax ) ) AS [ Total_sale_amt ]
I intend to to get a sales figure column additional to all other columns.
Below is what my table looks like
enter image description here
Thank you!
Seems like one of the column or some columns ( total_amt - ( Rate + Tax ) ) is varchar. Cast/Convert all the columns to int/Float/Decimal according to your requirement.
For the below query, i assume your totalamt, Rate, Tax are varchar fileds.
SELECT
customer_Id,
DOB,
DATEDIFF( MONTH, CONVERT ( date, Customer.DOB, 103 ),GETDATE ( ) ) AS [ Age IN Months ],
Gender,
city_code,
Qty,
( cast(total_amt as FLOAT) - ( cast(Rate as float) + cast(Tax as float)) ) AS [ Total_sale_amt ]
FROM Customer
JOIN Transactions
ON Customer.customer_Id = Transactions.cust_id
ORDER BY [ Age IN Months ] DESC;
The only subtract operator you have is:
(total_amt - (Rate + Tax)) AS [Total_sale_amt]
This suggests that one of these is a string -- and cannot be implicitly converted. I would suggest looking for these values:
select total_amt, rate, tax
from ? -- don't know which table these are in
where try_convert(decimal(20, 4), total_amt) is null or
try_convert(decimal(20, 4), rate) is null or
try_convert(decimal(20, 4), tax) is null;
This will show the offending values. You will need to fix the data or ask another question on how to fix the data -- once you know what needs to be fixed.

Query column twice with union all

I am trying to do a union all to produce data for reporting, below is what I have so far, it shows all the data I want but I cannot get the data in the same rows, it produces the two rows at a minimum with null in the corresponding column. I am hoping that there is a way so that I can get the data in the same row?
select account, campaign, sale, date
from
(
SELECT CHACCOUNTNO as account, CONTSUPREF as campaign,null as sale, ONDATE as date
FROM dbo.MKTDW
WHERE (RESULTCODE = 'D01') and CONTACT IN ('Campaign ID')
group by CHACCOUNTNO, CONTSUPREF, ONDATE
UNION ALL
SELECT CHACCOUNTNO as account, null as campaign, CONTSUPREF as sale, ONDATE as date
FROM dbo.MKTDW
WHERE (RESULTCODE = 'D01') and CONTACT IN ('Order')
group by CHACCOUNTNO, CONTSUPREF, ONDATE
)account
group by account,campaign,sale,date
order by account
Current Result:
account campaign sale date
A2043056003(2IJUMI M NULL N177618 2014-07-21 00:00:00.000
A2043056003(2IJUMI M LT08704 NULL 2014-07-21 00:00:00.000
Expected result:
A2043056003(2IJUMI M) LT08704 N177618 2014-07-21 00:00:00.000
The answer will be straightforward. If you want something shown in horizontal way, use JOINs instead of SET operators. The code is listed below, tested, works perfect in SSMS. :)
--create table structure
create table dbo.MKTDW
( CHACCOUNTNO varchar(100),
CONTSUPREF varchar(10),
RESULTCODE varchar(10),
CONTACT varchar(50),
ONDATE datetime)
go
--insert sample data
insert dbo.MKTDW
select 'A2043056003(2IJUMI M)', 'N177618', 'D01', 'Order', '2014-07-21 00:00:00.000'
union all
select 'A2043056003(2IJUMI M)', 'LT08704', 'D01', 'Campaign ID', '2014-07-21 00:00:00.000'
union all
select 'B2043056003(2IJUMI M)', 'M000000', 'D01', 'Order', '2014-07-21 00:00:00.000'
union all
select 'B2043056003(2IJUMI M)', 'X111111', 'D01', 'Campaign ID', '2014-07-21 00:00:00.000'
--below is the solution
select a.CHACCOUNTNO as account,
a.CONTSUPREF as campaign,
b.CONTSUPREF as sale,
a.ondate as date
from dbo.MKTDW as a
join dbo.MKTDW as b
on a.CHACCOUNTNO = b.CHACCOUNTNO
where a.CONTACT = 'campaign id'
and b.CONTACT = 'order'
and a.RESULTCODE = 'D01'
and b.RESULTCODE = 'D01'
RESULT:
There is no need of union all and specifying null ..
SELECT CHACCOUNTNO as account, CONTSUPREF as campaign,CONTSUPREF as sale, ONDATE as date
FROM dbo.MKTDW
WHERE (RESULTCODE = 'D01') and CONTACT IN ('Campaign ID','order')
group by CHACCOUNTNO, CONTSUPREF, ONDATE
When any of the above group by columns have null,Null will be treated as seperate group

Need help on DATE query in SQL server?

I have two tables in SQL Server:
EMP
On_Vacation with colums EmpId, LeaveType, StartingFrom, EndingTo,RejoiningDate
The On_Vacation table stores the information of employees who are on leave.
I'm trying to query the table in such a way that my query has the following columns:
EmpId, 24-1-2016, 25-1-2016, 26-1-2016, 27-1-2016, 28-1-2016
The result query columns are the dates of this week. If Employee is not on leave on these dates, it should write available. Otherwise it should write the leave type.
I'm very new to this type of queries, kindly help me experts..
You can't change the column name without dynamic sQL (which complicates matters).
Here's another suggestion: what is you change your date table to includes the name of the day of the week, like this:
CREATE TABLE DaysWeeks
(CalYear SMALLINT NOT NULL,
WeekNumber TINYINT NOT NULL,
CalDate DATE NOT NULL,
DayOfWeekNumber TINYINT,
DayOfWeekName VARCHAR(9)
CONSTRAINT PK_DaysWeeks PRIMARY KEY CLUSTERED (CalYear, WeekNumber, CalDate)
)
with values like this:
INSERT INTO dbo.DaysWeeks
( CalYear, WeekNumber, CalDate,DayOfWeekNumber,DayOfWeekName )
VALUES ( 2016, 4, '01/24/2016',1,'Sunday'),
( 2016, 4, '01/25/2016',2,'Monday'),
( 2016, 4, '01/26/2016',3,'Tuesday'),
( 2016, 4, '01/27/2016',4,'Wednesday'),
( 2016, 4, '01/28/2016',5,'Thursday'),
( 2016, 4, '01/29/2016',6,'Friday'),
( 2016, 4, '01/30/2016',7,'Saturday')
Now, you can have a query which pivots based on the day of the week:
WITH cte AS (
SELECT EmpDays.Employee, EmpDays.CalDate, EmpDays.DoWName, ISNULL(v.Leave_Type,'Available') AS Available
FROM dbo.On_Vacation v
RIGHT OUTER JOIN
(SELECT e.EmpID AS Employee, dw.CalDate AS CalDate, dw.DayOfWeekName AS DoWName
FROM dbo.DaysWeeks dw,
dbo.Employee e
WHERE dw.CalYear = 2016 AND dw.WeekNumber = 4) AS EmpDays
ON
v.EmpID = EmpDays.Employee
AND v.StartingFrom <= empdays.CalDate
AND v.EndingTo >= empdays.CalDate
)
SELECT * FROM cte
PIVOT (MAX(cte.Available) FOR DoWName IN (['Sunday'],['Monday'],['Tuesday'],['Wednesday'],['Thursday'],['Friday'],['Saturday'])
If your really need the actual dates in your columns, I would adjust this to use dynamic SQL. But before doing that (which, IMHO, makes the code much harder to read and maintain, not that this is so straightforward), I'd ask how you were going to present the data and therefore whether that might be handled in the report or presentation layer.
You would do this with conditional aggregation:
select e.empid,
coalesce(max(case when '2016-01-24' between v.startdate and v.enddate
then leave_type end),
'available') as [2016-01-14],
coalesce(max(case when '2016-01-25' between v.startdate and v.enddate
then leave_type end),
'available') as [2016-01-15],
. . .
from emp e left join
from vacation v
on e.empid = v.empid
group by e.empid;