datediff between multiple records in SQL - sql-server

I have one scenario where i want to get a count if date difference between the two dates is
<=14 days.That is in first table i have to filter records where any one value of DATE1 values are <=14 days of DATE2.
For Ex:
q1="SELECT DATE1 FROM DATE1_TABLE";
q2="SELECT DATE2 FROM DATE2_TABLE";
My simple query :
SELECT
COUNT(*)
FROM
DATE1_TABLE WHERE DATEDIFF(DD,DATE1,(SELECT DATE2 FROM DATE2_TABLE))<=14
But i have multiple records in both the tables,but i want to choose any record having
this difference then it will get a count >0.So,it is throwing error subquery returned more
than one record.I want some solutions for this.I am using SQL SERVER 2008
NOTE:I can't use join here.because i wanted results from two different queries.
Thanks in advance.

You can use TOP 1 clause in your query..
SELECT TOP 1 *
FROM DATE1_TABLE
WHERE DATEDIFF(DD,DATE1,(SELECT DATE2 FROM DATE2_TABLE))<=14

You cannot use SELECT which will return multiple values where function expects scalar value... however you can join those tables:
SELECT
COUNT(DISTINCT dt1.*)
FROM DATE1_TABLE dt1 INNER JOIN DATE2_TABLE dt2 ON DATEDIFF(DD,DATE1,DATE2)<=14
This query will join tables on values only when they are within 14 days and count on unique values from DATE1_TABLE. I have no idea if is it performance wise.

Related

SSRS: Why am I getting this aggregation?

I've recently uncovered that SSRS is doing a bizarre aggregation and I really don't understand why. In this report I'm building, as with other SQL queries I've built, I have a tendency to take preliminary results from an initial query, throw them into a temp table, and then perform another query and joining on that temp table to get my 'final' results I need to display. Here's an example:
--1. This query fetches all available rows based on the day (must be last day of month)
SELECT DISTINCT Salesperson ,c.Cust_Alias ,cost ,eomonth(CreateDate) createdate ,FaxNumber
INTO #equip
FROM PDICompany_2049_01.dbo.Customers c
JOIN PDICompany_2049_01.dbo.Customer_Locations cl ON c.Cust_Key = cl.CustLoc_Cust_Key
JOIN ricocustom..Equipment_OLD e ON e.FaxNumber = c.Cust_ID + '/' + cl.CustLoc_ID
JOIN PDICompany_2049_01.dbo.Charges ch ON ch.Chg_CustLoc_Key = cl.CustLoc_Key
WHERE Salesperson = #Salesperson
AND ch.Chg_Balance = 0
--2. This query fetches first result set, but filters further for matching date variable
SELECT DISTINCT (cost) EquipCost ,Salesperson ,DATEPART(YEAR, CreateDate) YEAR
,DATEPART(MONTH, CreateDate) MONTH ,Cust_Alias ,FaxNumber
INTO #equipcost
FROM #equip
WHERE Salesperson = #Salesperson
AND DATEPART(MONTH, CreateDate) = DATEPART(MONTH, #Start)
AND DATEPART(year, CreateDate) = DATEPART(year, #Start)
ORDER BY Cust_Alias
--3. Finally, getting sum of the EquipCost, with other KPI's, to put into my final result set
SELECT sum(EquipCost) EquipCost ,Salesperson ,YEAR ,MONTH ,Cust_Alias
INTO #temp_equipcost
FROM #equipcost
GROUP BY Salesperson ,year ,month ,Cust_Alias
Now I am aware that I could have easily reduced this to 2 queries instead of 3 in hindsight (and I have since gotten my results into a single query). But that's where I'm looking for the answer. In my GUI report, I had a row that was showing to have 180 for equipcost, but my query was showing 60. It wasn't until I altered my query to a single iteration (as opposed to the 3), and while I'm still getting the same result of 60, it now displays 60 in my GUI report.
I actually had this happen in another query as well, where I had 2 temp table result sets, but when I condensed it into one, my GUI report worked as expected.
Any ideas on why using multiple temp tables would affect my results via the GUI report in SQL Report Builder (NOT USING VB HERE!) but my SQL query within SSMS works as expected? And to be clear, only making the change described to the query and condensing it got my results, the GUI report in Report Builder is extremely basic, so nothing crazy regarding grouping, expressions, etc.
My best guess is that you accidentally had a situation where you did not properly clear the temp tables (or you populated the temp tables multiple times). As an alternative to temp tables, you could instead use table variables. Equally you could use a single query from the production tables -- using CTE if you want it to "feel" like 3 separate queries.

SQL Get Second Record

I am looking to retrieve only the second (duplicate) record from a data set. For example in the following picture:
Inside the UnitID column there is two separate records for 105. I only want the returned data set to return the second 105 record. Additionally, I want this query to return the second record for all duplicates, not just 105.
I have tried everything I can think of, albeit I am not that experience, and I cannot figure it out. Any help would be greatly appreciated.
You need to use GROUP BY for this.
Here's an example: (I can't read your first column name, so I'm calling it JobUnitK
SELECT MAX(JobUnitK), Unit
FROM JobUnits
WHERE DispatchDate = 'oct 4, 2015'
GROUP BY Unit
HAVING COUNT(*) > 1
I'm assuming JobUnitK is your ordering/id field. If it's not, just replace MAX(JobUnitK) with MAX(FieldIOrderWith).
Use RANK function. Rank the rows OVER PARTITION BY UnitId and pick the rows with rank 2 .
For reference -
https://msdn.microsoft.com/en-IN/library/ms176102.aspx
Assuming SQL Server 2005 and up, you can use the Row_Number windowing function:
WITH DupeCalc AS (
SELECT
DupID = Row_Number() OVER (PARTITION BY UnitID, ORDER BY JobUnitKeyID),
*
FROM JobUnits
WHERE DispatchDate = '20151004'
ORDER BY UnitID Desc
)
SELECT *
FROM DupeCalc
WHERE DupID >= 2
;
This is better than a solution that uses Max(JobUnitKeyID) for multiple reasons:
There could be more than one duplicate, in which case using Min(JobUnitKeyID) in conjunction with UnitID to join back on the UnitID where the JobUnitKeyID <> MinJobUnitKeyID` is required.
Except, using Min or Max requires you to join back to the same data (which will be inherently slower).
If the ordering key you use turns out to be non-unique, you won't be able to pull the right number of rows with either one.
If the ordering key consists of multiple columns, the query using Min or Max explodes in complexity.

SQL Server Stored Procedure get nearest available date to parameter

I have a table of database size information. The data is collected daily. However, some days are missed due to various reasons. Additionally we have databases which come and go over or the size does not get recorded for several databases for a day or two. This all leads to very inconsistent data collection regarding dates. I want to construct a SQL procedure which will generate a percentage of change between any two dates (1 week, monthly, quarterly, etc.) for ALL databases The problem is what to do if a chosen date is missing (no rows for that date or no row for one or more databases for that date). What I want to be able to do is get the nearest available date for each database for the two dates (begin and end).
For instance, if database Mydb has these recording dates:
2015-05-03
2015-05-04
2015-05-05
2015-05-08
2015-05-09
2015-05-10
2015-05-11
2015-05-12
2015-05-14
and I want to compare 2015-05-06 with 2015-05-14
The 2015-05-07 date is missing so I would want to use the next available date which is 2015-05-08. Keep in mind, MyOtherDB may only be missing the 2015-05-06 date but have available the 2015-05-07 date. So, for MyOtherDb I would be using 2015-05-07 for my comparison.
Is there a way to proceduralize this with SQL WITHOUT using a CURSOR?
You're thinking too much into this, simple do a "BETWEEN" function in your where clause that takes the two parameters.
In your example, if you perform the query:
SELECT * FROM DATABASE_AUDIT WHERE DATE BETWEEN param1 /*2015-05-06*/ and param2 /*2015-05-14*/
It will give you the desired results.
select (b.dbsize - a.dbsize ) / a.dbsize *100 dbSizecChangePercent from
( select top 1 * from dbAudit where auditDate = (select min(auditDate) from dbAudit where auditDate between '01/01/2015' and '01/07/2015')) a
cross join
(select top 1 * from dbAudit where auditDate = (select max(auditDate) from dbAudit where auditDate between '01/01/2015' and '01/07/2015')) b
The top 1 can be replaced by a group by. This was assuming only 1 db aduit per day

how to calculate all previous datas sum of a sql column on a date range report

I have a crystal report with debit credit columns using a sql command. This report contains a date to date filtering parameters. So the problem is if i filter the report to date range i need all the previous data sum using a sql command.
Select SUM(CAST(debit as DECIMAL(9,2)))- SUM(CAST(credit as DECIMAL(9,2)))
from sum_balance
where sum_date < sum_date
this is my code but i can't get the result from it. (e.g. : if the report starting from 2014-07-01 then i need the sum(debit - credit) of all previous data before 2014-07-01). Can anyone help me to find a solution for this. THe main thing is to add a brought forward balance using sql command on first row. If it is null then it should be 0.00.
Here is your sample table
CREATE TABLE #TEMP(DEBIT NUMERIC(20,2),CREDIT NUMERIC(20,2),DT VARCHAR(20))
INSERT INTO #TEMP
SELECT 1000 DEBIT,500 CREDIT,'2014-11-27' DT
UNION ALL
SELECT 2000 DEBIT,700 CREDIT,'2014-11-28' DT
UNION ALL
SELECT 3000 DEBIT,900 CREDIT,'2014-11-29' DT
I am updating answer for your updated requirement
QUERY 1
This will bring the total till current date, ie, for 2014-11-28 the amount will be (1000+2000)-(500+700), for 2014-11-29 the amount will be (1000+2000+3000)-(500+700+900)
SELECT T2.DEBIT,T2.CREDIT,T2.sum_date,
(SELECT SUM(DEBIT)-SUM(CREDIT) FROM sum_balance WHERE sum_date <= CAST(T2.sum_date AS DATE))
AMOUNT
FROM sum_balance T2
SQL FIDDLE
QUERY 2
This will bring the sum till previous day, that will be opening balance for today's date ie, for 2014-11-29 the amount will be (1000+2000)-(500+700). For easy understanding I have added the previous column also.
;WITH CTE AS
(
SELECT ROW_NUMBER() OVER(ORDER BY CAST(T2.sum_date AS DATE))RNO,
T2.DEBIT,T2.CREDIT,T2.sum_date,
ISNULL((SELECT SUM(DEBIT)-SUM(CREDIT) FROM sum_balance WHERE sum_date <= CAST(T2.sum_date AS DATE)),0)
AMOUNT
FROM sum_balance T2
)
SELECT C1.*,ISNULL(C2.AMOUNT,0) CARRYFORWARD
FROM CTE C1
LEFT JOIN CTE C2 ON C1.RNO=C2.RNO+1
SQL FIDDLE
You can use QUERY 2 and you will get opening balance till previous day in CARRYFORWARD column.
Please leave a message or comment for any changes.
When you need records previous than some date then you need to have that comparision date so that records can be extracted.
Your where clause where sum_date < sum_date won't work this way either you change the right side comparision operator in query or create a parameter in crystal so that user can enter the required end date during run time.
option 1:
E.g: where sum_date < currentdate
option 2:
Create a parameter and declare it in Record Selection Formula in crystal reports so that formed query will be something like
where sum_date < 2014-07-01
You can try this:-
SELECT SUM(CAST(debit as DECIMAL(9,2)))- SUM(CAST(credit as DECIMAL(9,2)))
FROM sum_balance
WHERE sum_date < (Select Max(sum_date) FROM sum_balance)

How do i find the total number of records created on a given day using T-SQL?

I need to find out the total number of records that were created on a given day.
e.g.
ID CreatedDate
1 17/07/2009
2 12/07/2009
3 17/07/2009
4 05/07/2009
5 12/07/2009
6 17/07/2009
Output:
3 Records were created on 17/07/2009
2 Records were created on 12/07/2009
1 Record was created on 05/07/2009
EDIT
Upon testing the second suggestion made by Chris Roberts of including the formatting in the SQL i get this error:
Syntax error converting the varchar value ' Records were created on ' to a column of data type int.
Does anyone know how to rework the solution so that it works?
You should be able to get the data you're after with the following SQL...
SELECT COUNT(ID), CreatedDate
FROM MyTable
GROUP BY CreatedDate
Or - if you want to do the formatting in the SQL, too...
SELECT CONVERT(varchar, COUNT(ID)) + ' Records were created on ' + CONVERT(varchar, CreatedDate)
FROM MyTable
GROUP BY CreatedDate
Good luck!
Is the column actually a timestamp? In which case you will need to apply a function to remove the time component, e.g.:
SELECT COUNT(*), date(CreatedDate) FROM MyTable GROUP BY date(CreatedDate)
I don't know what the function is in T-SQL, it's date() in MySQL and trunc() in Oracle. You may even have to do a to_string and remove the end of the string and group by that if you lack this.
Hope this helps.
select count(*), CreatedDate from table group by CreatedDate order by count(*) DESC

Resources