How to get selective count in sql - sql

i have a intermediate result as follows
year ID edition
1996 WOS:000074643400033 WOS.SCI
1996 WOS:000074643400033 WOS.ISSHP
1996 WOS:000074643400033 WOS.ISTP
2004 WOS:000222568300039 WOS.ISTP
2004 WOS:000222568300039 WOS.SCI
2008 WOS:000265048200175 WOS.ISTP
2009 WOS:000275179901182 WOS.ISTP
2009 WOS:000275179901182 WOS.ISSHP
now i must run a count on top of this result with the following conditions,
if a ID contain both "WOS.ISTP" and "WOS.ISSHP" edition in a same year, it must be counted just once.
my final table should look like the following.
Note: i have added the "intermediate_count" column just for understanding purpose, it need not appear in the final table.
year ID edition intermediate_count Final_count
1996 WOS:000074643400033 WOS.SCI 1 2
1996 WOS:000074643400033 WOS.ISSHP 1
1996 WOS:000074643400033 WOS.ISTP
2004 WOS:000222568300039 WOS.ISTP 1 2
2004 WOS:000222568300039 WOS.SCI 1
2008 WOS:000265048200175 WOS.ISTP 1 1
2009 WOS:000275179901182 WOS.ISTP 1 1
2009 WOS:000275179901182 WOS.ISSHP
i tried use CASE in the following way but didn't work out.
select id, year,
case
when edition_code = 'WOS.ISTP' and edition_code = 'WOS.ISSHP' then 'both'
else edition_code
end as edition_code_new
from table
group by id, year, edition_code_new
order by id;
any help would be appreciated, thanks in advance.

Assuming you want one row per id and year, you can use count(distinct):
select id, year,
count(distinct case when edition_code in ('WOS.ISTP', 'WOS.ISSHP')
then 'WOS.ISTP'
else edition_code
end) as count
from table
group by id, year
order by id;
You can also phrase this as a window function if you want the original rows.

Related

Total hours worked for employees in 2018 and 2019

I am new to stackoverflow and new to sql. I have employee timesheets which has a unique id and hours works by employees. I was wondering if theres a way to calculate the sum of the hours for each employee in 2018.
I dont know if this query is too basic but what i have so far is this:
select distinct PersonId, SUM(reghours) as '2018'
from TimeSheetsView
where left(yearweek,4)='2018'
group by PersonId, reghours
If you wanted to sum up both 2018 and 2019 in their own columns you could use a case statement to target those specific records in 2018 and 2019 placing them in their own column. You don't need a distinct with the group by either and like Mitch said you don't need that reghours it will split aggregation.
In the THEN piece it will sum up that field and ELSE is 0 so it won't obviously sum up any other rows that don't meet that condition.
Select PersonId
, SUM(CASE WHEN left(yearweek,4)='2018' THEN reghours ELSE 0 END) as '2018_RegHours'
, SUM(CASE WHEN left(yearweek,4)='2019' THEN reghours ELSE 0 END) as '2019_RegHours'
from TimeSheetsView
where left(yearweek,4) IN ('2018', '2019')
group by PersonId

How can I pivot and then calculate data?

Pretty new to SQL here. Thank you so much to anyone reading this.
I have a table
ProductID, Year, Sales
------------------------
Product1 2019 100
Product1 2018 50
With a lot of products, but the two years are always 2019 and 2018.
I need to show the 100 products that had the biggest % increase in sales.
I believe that this requires "pivoting" the data, so that you can calculate the 2019 (as one column) and 2018 (second column) difference in a third column called "% increase."
But I'm totally stuck--Ive never done anything this difficult in SQL before.
Help?
Another solution would be this, which would help you if there are more than one record per product - year:
SELECT
ProductId,
Sales_2018,
Sales_2019,
(Sales_2019 - Sales_2018) / Sales_2018 * 100 AS Percentage_increase
FROM (SELECT
ProductID,
SUM(CASE WHEN Year = 2018 THEN Sales END) AS Sales_2018,
SUM(CASE WHEN Year = 2019 THEN Sales END) AS Sales_2019
FROM TABLE
GROUP BY ProductID)
ORDER BY (Sales_2019 - Sales_2018) / Sales_2018 DESC
You can do this with self-join on almost any SQL engine.
Please find the sample implementation below.
You may need to fix some depending on the dialect that you use.
SELECT
a.ProductId,
(1.0 * b.Sales / a.Sales - 1.0) AS IncreaseRate
FROM
tbl AS a
INNER JOIN
tbl AS b
ON
a.ProductId = b.ProductId
AND a.year = 2018
AND b.year = 2019
ORDER BY
IncreaseRate DESC
LIMIT 100

How do I add two count columns to a result set when one count is not restricted by the arguments in the WHERE clause?

I was trying to write an SQL query that would return a set of data with a couple of count rows tacked on. In this case I want to return a list of FRUIT that are ROTTEN in the year 2018. I'd then like to tack on a column that counts the number of ROTTEN FRUIT found in the year 2018. Then another column that counts the total number of FRUIT rows, by type, for the year 2018.
So given the following table
FRUIT DEFECT YEAR ...
------------------------------
APPLE ROTTEN 2017
APPLE ROTTEN 2018
APPLE ROTTEN 2018
APPLE BUGS 2018
APPLE ROTTEN 2018
APPLE BUGS 2018
APPLE BITTEN 2018
APPLE BITTEN 2017
ORANGE BITTEN 2018
ORANGE ROTTEN 2018
I'd like to get the following result,
FRUIT DEFECT YEAR DEFECTCOUNT FRUITCOUNT
----------------------------------------------------
APPLE ROTTEN 2018 3 6
ORANGE ROTTEN 2018 1 2
but the problem is when I limit the where statement by searching for a specific DEFECT, I can't get the total for the FRUIT type for that year.
Here is my query so far
SELECT DISTINCT FRUIT
, Defect
, YEAR([Date]) As [YR]
, COUNT(Defect) AS [DEFECTCOUNT] -- This returns correctly
--, COUNT(*) AS [FRUITCOUNT] -- does return the correct number
FROM [dbo].[A_DETAIL_REPOS] dat
WHERE YEAR(dat.[Date]) >= '2018'
AND YEAR(dat.[Date]) <= '2018'
AND dat.Defect = 'ROTTEN'
GROUP BY FRUIT, Year([Date]), Defect
ORDER BY YEAR([Date])
Thank you for the help,
USE conditional COUNT() to get the rotten count.
SELECT FRUIT
--, Defect you only want 'ROTTEN' so you dont need this one
, YEAR([Date]) As [YR]
, COUNT( CASE WHEN Defect = 'ROTTEN' THEN 1 END ) AS [DEFECTCOUNT]
, COUNT(*) AS [FRUITCOUNT]
FROM [dbo].[A_DETAIL_REPOS] dat
WHERE YEAR(dat.[Date]) = '2018'
GROUP BY YEAR([Date]), FRUIT
You want conditional aggregation. However, I want to encourage you to use date comparisons for the filtering:
SELECT FRUIT, YEAR([Date]) As [YR],
SUM(CASE WHEN Defect = 'ROTTEN' THEN 1 ELSE 0 END) as num_rotten,
COUNT(*) as num_total
FROM [dbo].[A_DETAIL_REPOS] dat
WHERE r.[Date] >= '2018-01-01' AND
r.[Date] < '2019-01-01'
AND dat.Defect = 'ROTTEN'
GROUP BY FRUIT, Year([Date])
ORDER BY YEAR([Date]);
Direct date comparisons make it easier for the optimizer to produce the best query plan. In particular, it allows the use of an index, if appropriate.

SQL Server 2012 - find duplicate month (string) but different year

Having difficulty getting my head around this one.
I've been asked to create a report showing customers who signed up in the same month in previous year.
Invoice table looks a bit like this: (can't figure out how to create a nicer table)
invoiceid customerid monthinvoice yearinvoice
1 50 July 2016*
2 51 July 2016
3 52 July 2016*
4 53 July 2016
5 54 August 2016
6 50 July 2017*
7 51 August 2017
8 52 July 2017*
9 53 August 2017
10 54 September 2017
The only proper date column used is date the invoice was generated and the date payment received.
The records marked with * are the ones I'm only interested in, I just want to see 2 records returned when I pass a month as a parameter (I'll be asked to show how many customers have renewed in August for example. If the 1st invoice was in July 2016 and next invoice in August 2017 they will be treated as a new customer, not a renewal (must be exactly 12 months))
1) 50
2) 52
Any help much appreciated.
Here is one way. First we get all invoices for this month, current year, then union to the same month of the previous year. Then, we filter on customers who have a record for both using HAVING.
;with cte as(
select *
from yourtable
where
(monthinvoice = #monthinvoice
and yearinvoice = datepart(year,getdate()))
union
select *
from yourtable
where
(monthinvoice = #monthinvoice
and yearinvoice = datepart(year,dateadd(year,-1,getdate()))))
select *
from cte
where customerid in (select customerid from cte group by customerid having count(invoiceid) > 1)
I think this should do the trick for you-
SELECT I1.invoiceid, I1.customerid, I1.monthinvoice, I1.yearinvoice, I2.yearinvoice
FROM Invoice_table I1
INNER JOIN Invoice table I2
ON I1.customerid = I2.customerid
AND I1.monthinvoice = I2.monthinvoice
AND I1.yearinvoice = I2.yearinvoice + 1
something like this
select customerid , monthinvoice from yourtable
where yearinvoice in (2016, 2017) and monthinvoice = 'July'
group by customerid , monthinvoice
having count(*) = 2
Something like the following should give you some ideas as to how to build the report out.
Declare #ReportYear as int = 2017;
--this should show all customers with invioices for these months in both 2017 and 2016
select a.customerid, a.monthinvoice
from
(
--get people with invoice last year
Select distinct customerid, monthinvoice
from Invoices i0
where yearinvoice = #ReportYear - 1
) a
join
(
--get people with invoice this year
Select distinct customerid, monthinvoice
from Invoices i0
where yearinvoice = #ReportYear
) b on a.customerid = b.customerid
and a.monthinvoice = b.monthinvoice
If Im following your question correctly...
SELECT customerid FROM InvTblName T
INNER JOIN (SELECT customerID
FROM InvTblName
HAVING Z.invyear=T.invyear+1) Z
ON T.invmonth=Z.invmonth

T-SQL query to select last 3 months of data, last years month, averages of this month and average of all months

I have a table with columns Category, Date, Monthly_Revenue.
I need a query that will select Todays_Month, Last_Month, 2 months prior, Last_years_Month, average of today's month, average of all months.
This query is needed grouped by category.
Example :
Category | Sept, 2012 | Aug, 2012| Jul, 2012 | Sept, 2011 | Average of Sept | Avg all Mo
Being fairly new to SQL I still haven't got it yet. I figured see if somebody out there could take a crack at it. Thanks.
Sample data
'Burger' '9/1/2012' '500'
'Fries' '10/1/2012 '300'
'Burger' '6/1/2011' '250'
you need something along these lines .Not the optimum solution but will give you a start
.This is a static solution but it looks like you may want a dynamic solution
*not tested
SELECT
Category
,[Sep 2012]=SUM(CASE WHEN YEAR(TranDate)= YEAR(GETDATE()) AND MONTH(TranDate)= MONTH(GETDATE()) THEN Amount ELSE NULL END)
,[Aug 2012]=SUM(CASE WHEN YEAR(TranDate)= YEAR(DATEADD(month,-1,GETDATE())) AND MONTH(TranDate)= MONTH(DATEADD(month,-1,GETDATE())) THEN Amount ELSE NULL END)
,[Jul 2012]=SUM(CASE WHEN YEAR(TranDate)= YEAR(DATEADD(month,-2,GETDATE())) AND MONTH(TranDate)= MONTH(DATEADD(month,-2,GETDATE())) THEN Amount ELSE NULL END)
,[AVG Sep 2012]=AVG(CASE WHEN YEAR(TranDate)= YEAR(GETDATE()) AND MONTH(TranDate)= MONTH(GETDATE()) THEN Amount ELSE NULL END)
,[AVG 12 months]=AVG(CASE WHEN TranDatee > CAST(DATEADD(year,-1,GETDATE()) AS DATE) THEN Amount ELSE NULL END)/12
FROM Table1
GROUP BY Category,Amount