Related
I have some issue about how to make query result like
this is what i've tried,, but not exactly same like what i mean
CREATE TABLE #dta
(
Data [nvarchar](max),
Date [varchar] (12) ,
GR [int] ,
Refund [int] ,
Sales [int] ,
)
INSERT INTO #dta
SELECT 'asd',1,10,0,0 UNION ALL
SELECT 'asd',2,0,0,4 UNION ALL
SELECT 'asd',3,4,1,1 UNION ALL
SELECT 'qwe',1,2,0,0 UNION ALL
SELECT 'qwe',3,0,0,1 UNION ALL
SELECT 'zxc',1,0,0,5 UNION ALL
SELECT 'zxc',2,4,0,1 UNION ALL
SELECT 'zxc',3,0,1,5
--Only for sales
SELECT data, [1],[2],[3] FROM
(SELECT data, [date] , Sales FROM #dta )Tab1
PIVOT
(
SUM(Sales) FOR [date] IN ([1],[2],[3])) AS Tab2
ORDER BY Tab2.Data
You can use conditional aggregation and try something along this code:
SELECT t.[Data]
,MAX(CASE WHEN t.[Date]=1 THEN t.Sales END) AS [Sales_Date_1]
,MAX(CASE WHEN t.[Date]=1 THEN t.Refund END) AS [Refund_Date_1]
,MAX(CASE WHEN t.[Date]=1 THEN t.GR END) AS [GR_Date_1]
,MAX(CASE WHEN t.[Date]=2 THEN t.Sales END) AS [Sales_Date_2]
,MAX(CASE WHEN t.[Date]=2 THEN t.Refund END) AS [Refund_Date_2]
,MAX(CASE WHEN t.[Date]=2 THEN t.GR END) AS [GR_Date_2]
,MAX(CASE WHEN t.[Date]=3 THEN t.Sales END) AS [Sales_Date_3]
,MAX(CASE WHEN t.[Date]=3 THEN t.Refund END) AS [Refund_Date_3]
,MAX(CASE WHEN t.[Date]=3 THEN t.GR END) AS [GR_Date_3]
FROM #dta t
GROUP BY t.[Data];
If the count of t.[Date] (1 to 3 in your example data) is not limited to a known maximum, you'd have to create the statement dyanmically.
If your t.[Date] column is a date value actually and you want your output columns named after some date values (unpredictable column alias) within your set, you must create this dynamically too.
I have a query that I have been using to track users sales. Previously they ere required to make a quota each month. Now, however they would like to change the rule to allow them to start any month, so they may go from June to June or whatever. they also want users to start over immediately if they miss a month. This does seem to be a more equitable system because if they didn't make the quota in March, for example, they were unable to count any they made after that month for the entire year. This really messes up my query though, and I don't know how to fix it. anyone have a solution?
here is the existing t-sql.
#Year int
AS
BEGIN
DECLARE #DateStart datetime
DECLARE #DateStop datetime
SELECT #DateStart = CONVERT(DATETIME, CONVERT( char(4), #Year) + '-01- 01')
SELECT #DateStop = CONVERT(DATETIME, CONVERT( char(4), #Year + 1) + '-01- 01')
SET NOCOUNT ON;
SELECT r.riderid,
r.dname,
DATEPART(yyyy, m.ridedate),
SUM(CASE DATEPART(mm, m.datesale) WHEN 1 THEN m.quota ELSE 0 END) AS [jan],
SUM(CASE DATEPART(mm, m.datesale) WHEN 2 THEN m.quota ELSE 0 END) AS [feb],
SUM(CASE DATEPART(mm, m.datesale) WHEN 3 THEN m.quota ELSE 0 END) AS [mar],
SUM(CASE DATEPART(mm, m.datesale) WHEN 4 THEN m.quota ELSE 0 END) AS [apr],
SUM(CASE DATEPART(mm, m.datesale) WHEN 5 THEN m.quota ELSE 0 END) AS [may],
SUM(CASE DATEPART(mm, m.datesale) WHEN 6 THEN m.quota ELSE 0 END) AS [jun],
SUM(CASE DATEPART(mm, m.datesale) WHEN 7 THEN m.quota ELSE 0 END) AS [jul],
SUM(CASE DATEPART(mm, m.datesale) WHEN 8 THEN m.quota ELSE 0 END) AS [aug],
SUM(CASE DATEPART(mm, m.datesale) WHEN 9 THEN m.quota ELSE 0 END) AS [sep],
SUM(CASE DATEPART(mm, m.datesale) WHEN 10 THEN m.quota ELSE 0 END) AS [oct],
SUM(CASE DATEPART(mm, m.datesale) WHEN 11 THEN m.quota ELSE 0 END) AS [nov],
SUM(CASE DATEPART(mm, m.datesale) WHEN 12 THEN m.quota ELSE 0 END) AS [dec],
SUM(m.quota) as [tot]
FROM users u
JOIN mysales m
ON m.riderid = u.riderid
Where m.datesale Between #DateStart AND #DateStop
GROUP BY DATEPART(yyyy, m.datesale), u.userid
ORDER BY DATEPART(yyyy, m.datesale), SUM(m.quota) DESC
END
OK -here is data
The table holds the users id, the customer id , amount of sale and date of sale
The query pulls the user, the sum of sales by month. User 250 made quota in July/2016, but did not in August, so he should get an entry in #quota for July, and September, but because he did not in August he has to restart in September; user# 300 has made quota from Jan 2016 to SEPT so he has qualified for his bonus as long as he finishes the 12 months. User 350 has successfully finished the year and should get a bonus. at this time in prod there is no quota table, would that simplify? What I need is a list of users that are in the running.
--drop table #sales
--drop table #quota
create table #sales
(
--saleid int --PK
userid int -- salesperson FK
, customerid int --FK
, sale_amt decimal
, date_sale datetime
)
insert into #sales values
(300,1301,542.90,'3-2-2016'),
(300,1301,782.70,'3-4-2016'),
(300,1541,600.70,'3-7-2016'),
(300,903,640.71,'3-10-2016'),
(300,1745,900.01,'3-29-2016'),
(300,1440,2040.71,'2-10-2016'),
(300,903,640.71,'2-20-2016'),
(300,414,1489.00,'1-18-2016'),
(300,1645,1322.00,'1-20-2016'),
(300,1200,1156.09,'4-2-2016'),
(300,1204,1456.00,'4-20-2016'),
(250,1140,156.89,'4-12-2016'),
(250,1240,1176.69,'4-14-2016'),
(250,840,480.61,'4-17-2016'),
(250,1940,500.71,'5-17-2016'),
(250,1425,4800.61,'6-1-2016'),
(250,1840,701.32,'6-15-2016'),
(250,1840,701.32,'7-15-2016'),
(250,1840, 2701.32,'8-15-2016'),
(450,8421,2500.61,'7-17-2015'),
(450,8422,2500.1,'8-17-2015'),
(450,843,2500.1,'9-17-2015'),
(450,8431,2500.00,'10-17-2015'),
(450,1431,2500.00,'11-17-2015'),
(450,4311,2500.00,'12-17-2015'),
(450,4310,2500.00,'1-17-2016'),
(450,1310,2500.00,'2-17-2016'),
(450,1310,2500.00,'3-17-2016'),
(450,130,2500.00,'4-17-2016'),
(450,1130,2500.00,'5-17-2016'),
(450,113,2500.00,'6-17-2016')
Select userid
, sum(sale_amt) Sale
, DATEPART(mm,date_sale) as[month]
from #sales
group by userid, DATEPART(mm,date_sale) order by userid
create table #quota
(
qid int --PK
, userid int -- salesperson FK
, quota bit -- awarded when sales => $2500.00
, datesale datetime -- date quota made
)
Just one possible way to write a query that looks back #running_months number of months to verify that no quotas have been missed during the window for each user:
select userid from users u
where not exists (
select 1 from #sales s
where s.userid = u.userid
and date_sale > dateadd(month, -#running_months - 1, current_timestamp)
and datediff(month, sales_date, current_timestamp) between 1 and #running_months
group by month(sales_amt)
having sum(sales_amt) < 2500
)
EDIT: I later realized that you probably do have users with no sales during a month so you'll probably need to actually verify the condition that all the months are over quota rather than none of the months are under quota:
select userid from users u
where userid in (
select userid from
(
select userid from #sales s
where s.userid = u.userid
and date_sale > dateadd(month, -#running_months - 1, current_timestamp)
and datediff(month, sales_date, current_timestamp) between 1 and #running_months
group by month(sales_amt)
having sum(sales_amt) >= 2500
) q
group by userid
having count(*) = #running_months
)
Hi I am trying to duplicate a complex IIF function I used in MS Access but can't seem to translating it into a SLQ 2008 using CASE. I am trying to create a WHERE clause something like this
.....
WHERE
(IIF([Created Date]= NULL, IIF(DATEDIFF(day,[Created Date],[POSTED Date])<=3,1,IIF([Created Date] BETWEEN [Disti Reported Sales Date] AND [Posted Date]),1,NULL)))=1
AND
......
Basically what its doing is looking at a date from one column and comparing it to two other columns but if one of the columns is NULL then it uses a different comparison.
The literal translation should look close to this:
WHERE (CASE
WHEN [Created Date] IS NULL
THEN (CASE
WHEN DATEDIFF(DD, [Created Date], [POSTED Date]) <= 3
THEN 1
ELSE (CASE
WHEN [Created Date] BETWEEN [Disti Reported Sales Date] AND [Posted Date]
THEN 1
ELSE 0
END)
END)
ELSE 0
END) = 1
However, this can be simplified to something like this:
WHERE (CASE
WHEN [Created Date] IS NULL AND DATEDIFF(DD, [Created Date], [POSTED Date]) <= 3 THEN 1
WHEN [Created Date] IS NULL AND [Created Date] BETWEEN [Disti Reported Sales Date] AND [Posted Date] THEN 1
ELSE 0 END) = 1
As noted in my comment, it still seems odd that if [Created Date] IS NULL, you are trying to still use it in any calculation.
I have 4 result sets which i moved into one temp table for report purpose:
Date Issued_Id Item_Name Qty_Issued Qty_Return Qty_Damage Type Balance OPBal
----------------------------------------------------------------------------------------------
Dec 18 2014 6003 Bed Covers 4 0 0 IS NULL 245
Dec 18 2014 6008 Bed Covers 4 0 0 IS NULL 245
2014-12-17 6000 Bed Covers 0 22 0 RT NULL 245
2014-12-22 7002 Bed Covers 0 10 0 RT NULL 245
Now I have to add (OPBal=Qty_Issued + OPBal) when Type="IS" and subtract (OPBal=Qty_Return - OPBal) when type="RT".
It should print like this way
Date Issued_Id Item_Name Qty_Issued Qty_Return Qty_Damage Type Balance OPBal
---------------------------------------------------------------------------------------------
Dec 18 2014 6003 Bed Covers 4 0 0 IS NULL 249
Dec 18 2014 6008 Bed Covers 4 0 0 IS NULL 253
2014-12-17 6000 Bed Covers 0 22 0 RT NULL 231
2014-12-22 7002 Bed Covers 0 10 0 RT NULL 221
How can I achieve using cursor in SQL Server?
It's unclear what the sort criteria are for the four rows in your question — it's neither by date nor by Issued_Id. I'm going to assume that the entries should be ordered by Issued_Id, and that your example is a mistake.
The simplest way to get a cumulative sum is to use a window query.
SELECT Date, Issued_Id, Item_Name, Qty_Issued, Qty_Return, Qty_Damage, Type, Balance
, SUM(
CASE WHEN Type='IS' THEN Qty_Issued
WHEN Type='RT' THEN -Qty_Return
END
) OVER (
ORDER BY Issued_Id ROWS UNBOUNDED PRECEDING
) + OPBal AS OPBal
FROM #Temp1
ORDER BY Issued_Id;
It might even be possible to simplify it by ignoring the Type column and the CASE expression altogether.
SELECT Date, Issued_Id, Item_Name, Qty_Issued, Qty_Return, Qty_Damage, Type, Balance
, SUM(Qty_Issued - Qty_Return)
OVER (ORDER BY Issued_Id ROWS UNBOUNDED PRECEDING) + OPBal AS OPBal
FROM #Temp1
ORDER BY Issued_Id;
The setup for the queries above:
CREATE TABLE #Temp1
( Date DATE NOT NULL
, Issued_Id INTEGER NOT NULL
, Item_Name VARCHAR(32) NOT NULL
, Qty_Issued DECIMAL NOT NULL DEFAULT 0
, Qty_Return DECIMAL NOT NULL DEFAULT 0
, Qty_Damage DECIMAL NOT NULL DEFAult 0
, Type VARCHAR(2) NOT NULL
, Balance DECIMAL
, OPBal DECIMAL NOT NULL
);
INSERT INTO #Temp1 VALUES
('2014-12-18', 6003, 'Bed Covers', 4, 0, 0, 'IS', NULL, 245),
('2014-12-18', 6008, 'Bed Covers', 4, 0, 0, 'IS', NULL, 245),
('2014-12-17', 6000, 'Bed Covers', 0, 22, 0, 'RT', NULL, 245),
('2014-12-22', 7002, 'Bed Covers', 0, 10, 0, 'RT', NULL, 245);
Try this
SELECT [Date],
Issued_ID,
Item_Name,
Qty_Issued,
Qty_Return,
Qty_Damage,
[Type],
Balance,
OPBal= CASE
WHEN TYPE = 'IS' THEN Qty_Issued + OPBal
WHEN TYPE = 'RT' THEN Qty_Return - OPBal
ELSE 0
END
FROM #TEMP
It is not clear what your records are to be ordered by. It seems to be Date (oldest first) and Issue_Id (smallest first). If I am wrong abot this, simply change the order by clauses in below statement according to your wishes.
What you are looking for is a kind of running total, where conditionally Qty_Issued and Qty_Return get summed up. You achive this by an analytic use of SUM with a window clause.
SELECT [Date], Issued_Id, Item_Name, Qty_Issued, Qty_Return, Qty_Damage, Type, Balance,
OPBal
+ SUM(case when type = 'IS' then Qty_Issued else 0 end) OVER (ORDER BY [Date] desc, issue_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
- SUM(case when type = 'RT' then Qty_Return else 0 end) OVER (ORDER BY [Date] desc, issue_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS OPBal
FROM mytable
ORDER BY [Date] desc, issue_id;
As you have zeros in your data for Qty_Issued and Qty_Return where they are not appropriate, you might also simply be able to use:
SELECT [Date], Issued_Id, Item_Name, Qty_Issued, Qty_Return, Qty_Damage, Type, Balance,
OPBal
+ SUM(Qty_Issued - Qty_Return) OVER (ORDER BY [Date] desc, issue_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS OPBal
FROM mytable
ORDER BY [Date] desc, issue_id;
CREATE TABLE #TT
(
[Date] DateTime,
Issued_Id VARCHAR(100),
Item_Name VARCHAR(100),
Qty_Issued INT,
Qty_Return INT,
Qty_Damage INT,
[Type] VARCHAR(100),
Balance INT,
OPBal INT
)
INSERT INTO #TT
SELECT 'Dec 18 2014', 6003,' Bed Covers ', 4,0,0,'IS', NULL,245 UNION ALL
SELECT 'Dec 18 2014', 6008,' Bed Covers ', 4,0,0,'IS', NULL,245 UNION ALL
SELECT '2014-12-17', 6000,' Bed Covers ', 4,22,0,'RT', NULL, 245 UNION ALL
SELECT '2014-12-22', 7002,' Bed Covers ', 4,10,0,'RT', NULL,245
--- IF you want to apply this logic with out any sort(as shown in your question)
SELECT [Date],Issued_Id, Item_Name, Qty_Issued, Qty_Return, Qty_Damage, Type, Balance,
OPBal
+ SUM(case when type = 'IS' then Qty_Issued else 0 end) OVER (ORDER BY (SELECT 1) ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
- SUM(case when type = 'RT' then Qty_Return else 0 end) OVER (ORDER BY (SELECT 1) ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS OPBal
FROM #TT
--- IF you want to order records by [Date] & issued_id then apply this logic
SELECT [Date],Issued_Id, Item_Name, Qty_Issued, Qty_Return, Qty_Damage, Type, Balance,
OPBal
+ SUM(case when type = 'IS' then Qty_Issued else 0 end) OVER (ORDER BY [Date] ASC, issued_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
- SUM(case when type = 'RT' then Qty_Return else 0 end) OVER (ORDER BY [Date] ASC, issued_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
AS OPBal
,SUM(case when type = 'IS' then Qty_Issued else 0 end) OVER (ORDER BY [Date] ASC, issued_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
,SUM(case when type = 'RT' then Qty_Return else 0 end) OVER (ORDER BY [Date] ASC, issued_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
FROM #TT
Thanks to everyone..
I got solution using cursor and case...
DECLARE db_cursor CURSOR for select id from #Temp1;
open db_cursor
fetch next from db_cursor into #varData
while ##FETCH_STATUS=0
begin
set #LastAmt = ( select OPBal= case
when Type='IS' then #LastAmt+Qty_Issued
when type='RT' then #LastAmt-(Qty_Return+Qty_Damage)
when type='OP' then OPBal
else 0
end
from #Temp1 where id = #varData)
update #Temp1 set OPBal= #LastAmt where id = #varData
FETCH NEXT
FROM db_cursor INTO #varData
END
CLOSE db_cursor
DEALLOCATE db_cursor
select * from #Temp1
I have the following query
SELECT MONTH, COUNT(DISTINCT VISITS) AS BRAND_VISITS, NULL AS NONB_VISITS
FROM Table1
WHERE KEYWORD_TYPE = BRAND(
AND DATE >= '2013-01-01'
GROUP BY MONTH
UNION ALL
SELECT MONTH, NULL, COUNT(DISTINCT VISITS) AS NONB_VSTS
FROM Table1
WHERE KEYWORD_TYPE = NON-BRAND
AND DATE >= '2013-01-01'
GROUP BY MONTH
I get the following results:
1 352540 NULL
2 309834 NULL
3 228764 NULL
4 236054 NULL
5 218096 NULL
6 172527 NULL
1 NULL 5337
2 NULL 14120
3 NULL 9954
4 NULL 23755
5 NULL 19771
6 NULL 30797
However, what I want is inline results without NULLS
1 352540 5337
2 309834 14120
3 228764 9954
4 236054 23755
5 218096 19771
6 172527 30797
You can do this with using a single statement with CASE or with an JOIN on month instead of a UNION. If you take the join approach you may need to account for null values (no visist for a keyword in a month). You will want to profile them to see which is faster with your data and table structure. It is really all about the indexes and the amount of data you need to aggregate.
Assuming you don't have to worry about nulls based on the counts in your example, here is what you want.
SELECT brand.month, brand.brand_visits,nonbrand.non_brand_visits
FROM (SELECT month, COUNT(visits) AS brand_visits
FROM Table1
WHERE keyword_type = 'BRAND'
AND date >= '2013-01-01'
GROUP BY month) brand
INNER JOIN
(SELECT month, COUNT(visits) AS non_brand_visits
FROM Table1
WHERE keyword_type = 'NON-BRAND'
AND date >= '2013-01-01'
GROUP BY month) nonbrand
ON brand.month=nonbrand.month
Here is the CASE approach. You should profile based on your actual data you are aggregating and your indexes to see which method is faster.
SELECT month,
SUM(CASE WHEN keyword_type = 'BRAND' THEN 1 ELSE 0 END) AS brand_visits,
SUM(CASE WHEN keyword_type = 'NON-BRAND' THEN 1 ELSE 0 END) AS non_brand_visits
FROM Table1
WHERE date >= '2013-01-01'
GROUP BY month
Finally, you did not provide table structure or example data so I made some assumptions above. I strongly believe you did not need the COUNT(DISTINCT in your original statement. I have removed it and verified the two statement above yield the same results. If COUNT(DISTINCT is required then the CASE approach will not work but the join approach will still work fine.
Using your columns:
SELECT month,
count(distinct CASE WHEN keyword_type = 'BRAND' THEN visits END) AS BRAND_VISITS,
count(distinct CASE WHEN keyword_type = 'NON-BRAND' THEN visits END) AS NONB_VSTS
FROM Table1
WHERE date >= '2013-01-01'
and keyword_type in ('BRAND','NON-BRAND')
GROUP BY month
Am tempted to believe that month is simply the month from the date column, I would prefer this solution, it con cover more years than 1 and the same query will still be valid in the year 2014
SELECT cast(dateadd(month, datediff(month, 0, date), 0) as date) month,
count(distinct CASE WHEN keyword_type = 'BRAND' THEN visits END) AS BRAND_VISITS,
count(distinct CASE WHEN keyword_type = 'NON-BRAND' THEN visits END) AS NONB_VSTS
FROM Table1
WHERE date >= '2013-01-01'
and keyword_type in ('BRAND','NON-BRAND')
GROUP BY datediff(month, 0, date)
If you want to stick with your old script, you can fix it this way:
SELECT MONTH, max(BRAND_VISITS) BRAND_VISITS, max(NONB_VISITS) NONB_VISITS
FROM
(
SELECT MONTH, COUNT(DISTINCT VISITS) AS BRAND_VISITS, NULL AS NONB_VISITS
FROM Table1
WHERE KEYWORD_TYPE = 'BRAND'
AND DATE >= '2013-01-01'
GROUP BY MONTH
UNION ALL
SELECT MONTH, NULL, COUNT(DISTINCT VISITS) AS NONB_VSTS
FROM Table1
WHERE KEYWORD_TYPE = 'NON-BRAND'
AND DATE >= '2013-01-01'
GROUP BY MONTH
) a
GROUP BY MONTH