How to create a view from these 2 tables? - sql-server

Table 1
bln thn qty1
1 2014 10
1 2014 20
2 2014 30
3 2014 40
2 2014 50
4 2014 60
Table 2
bln thn qty2
3 2014 200
5 2014 400
2 2014 100
2 2014 500
4 2014 300
6 2014 600
New View
bln thn qty1 qty2
1 2014 30 0
2 2014 80 600
3 2014 40 200
4 2014 60 300
5 2014 0 400
6 2014 0 600
From 2 tables at top, i'd like to create a view like table in the bottom.
Anyone would like to help ? :D thanks

I have made same Select as #JohnBevan but with some changes (not using Grouping on main select, also he forgot to name inner select columns)
DECLARE #table1 TABLE (bln INT, thn INT, qty1 INT)
INSERT INTO #table1 SELECT 1,2014,10
INSERT INTO #table1 SELECT 1,2014,20
INSERT INTO #table1 SELECT 2,2014,30
INSERT INTO #table1 SELECT 3,2014,40
INSERT INTO #table1 SELECT 2,2014,50
INSERT INTO #table1 SELECT 4,2014,60
DECLARE #table2 TABLE (bln INT, thn INT, qty2 INT)
INSERT INTO #table2 SELECT 3,2014,200
INSERT INTO #table2 SELECT 5,2014,400
INSERT INTO #table2 SELECT 2,2014,100
INSERT INTO #table2 SELECT 2,2014,500
INSERT INTO #table2 SELECT 4,2014,300
INSERT INTO #table2 SELECT 6,2014,600
CREATE VIEW NewView AS
SELECT COALESCE(T1.bln, T2.bln) AS bln
, COALESCE(T1.thn, T2.thn) AS thn
, COALESCE(T1.qty1, 0) AS qty1
, COALESCE(T2.qty2, 0) AS qty2
FROM (
SELECT bln, thn, SUM(qty1) AS qty1
FROM #table1
GROUP BY bln, thn
) AS T1
FULL JOIN (
SELECT bln, thn, SUM(qty2) AS qty2
FROM #table2
GROUP BY bln, thn
) AS T2
ON T1.bln = T2.bln
AND T1.thn = T2.thn
SQLFiddle: http://sqlfiddle.com/#!6/a3e2b/1

--create a new view called newview
create view NewView as
--if table1 has a record for this bln use it; otherwise take table 2's value
select coalesce(t1.bln,t2.bln) bln
--same for thn
, coalesce(t1.thn,t2.thn) thn
--take the sum of qty1 calculated below (max used just because we need an aggregate - they're all the same
, max(t1.qty1) qty1
--same for qty2
, max(t2.qty2) qty2
--select from the tables summing the quantities here (so we have a 1:1 match on the join / don't have to sum for every match)
from (select bln, thn, sum(qty1) as qty1 from table1 group by bln, thn) t1
full outer join (select bln, thn, sum(qty2) as qty2 from table2 group by bln, thn) t2
on t1.bln = t2.bln
and t1.thn = t2.thn
--group by the common fields so we get 1 record per value combination
group by t1.bln, t2.bln, t1.thn, t2.thn
SQLFiddle: http://sqlfiddle.com/#!6/708da/1

Related

Query show Retail Item with Itemset in Ms Sql

I have a task to show the query result like below:
Table 1 item show one time and Table 2 table have related record than show that details.
Kindly look below example
Table 1:
ItemNumber Retail_Price IsItemSet
5000 10000 Y
5001 5000 N
Table 2:
ItemNumber item_DetailsNo Retail_Price
5000 10 2000
5000 11 8000
I want result like below:
ItemNumber Retail_Price
5000 10000
5000 8000
5000 2000
5001 5000
Result in a single query.
use UNION
select ItemNumber,Retail_Price from table1
union
Select ItemNumber,Retail_Price from table2
order by ItemNumber,Retail_Price desc
Output
Try this -
select ItemNumber, Retail_Price
From Table1
Union All
select ItemNumber, Retail_Price
From Table2
Order by ItemNumber, Retail_Price Desc
create table #Table1 (ItemNumber int, Retail_Price int, IsItemSet varchar(4))
insert into #Table1 values
(5000,10000,'Y'),(5001, 5000,'N')
create table #Table2 (ItemNumber int, item_DetailsNo int, Retail_Price int)
insert into #Table2 values
(5000,10,2000),(5000,11,8000)
select ItemNumber, Retail_Price from #Table1
UNION
select ItemNumber,Retail_Price from #Table2
drop table #Table1
drop table #Table2
OUTPUT
ItemNumber Retail_Price
5000 2000
5000 8000
5000 10000
5001 5000

How to get previous record if current record does not exist in table

my table like this
Id Date type quantity
1 29/04/2019 APPLE 2
2 29/04/2019 Banana 15
3 29/04/2019 Mango 100
4 29/04/2019 Grapes 50
5 29/04/2019 Fish 80
6 30/04/2019 APPLE 4
7 30/04/2019 Grapes 100
8 30/04/2019 Fish 90
9 01/05/2019 APPLE 6
10 01/05/2019 Banana 30
11 01/05/2019 Grapes 150
12 01/05/2019 Fish 100
13 02/05/2019 Mango 200
14 02/05/2019 Grapes 200
15 02/05/2019 Fish 110
16 03/05/2019 APPLE 8
17 03/05/2019 Banana 45
18 03/05/2019 Mango 300
19 04/05/2019 APPLE 10
20 04/05/2019 Grapes 300
21 04/05/2019 Fish 120
22 05/05/2019 APPLE 12
23 05/05/2019 Fish 130
i miss some inputs every day,But i need to fill the gaps with previous row of the same "Type" on 30/04/2019 i missed "Banana & Mango" bu i need like
Id Date type quantity
1 29/04/2019 APPLE 2
2 29/04/2019 Banana 15
3 29/04/2019 Mango 100
4 29/04/2019 Grapes 50
5 29/04/2019 Fish 80
6 30/04/2019 APPLE 4
7 30/04/2019 Grapes 100
8 30/04/2019 Fish 90
9 30/04/2019 Banana 15
10 30/04/2019 Mango 100
actually last two rows are null but it should updated same on 29/04/2019
I think the easiets way might be this:
DECLARE #PDate DATE = SELECT TOP 1 Date FROM YourTable ORDER BY Date ASC --Previous Date
DECLARE #NDate DATE = SELECT TOP 1 Date FROM YourTable WHERE DATE>#PDate --Next Date
WHILE (#NDate IS NOT NULL)
BEGIN
WITH X AS
(
SELECT T1.Date AS Date1, T1.Type AS Type1, T1.Quantity AS Q1
T2.Date AS Date2, T2.Type AS Type2, T2.Quantity AS Q2
FROM YourTable T1
LEFT JOIN YourTable T2 ON T1.Type = T2.Type
WHERE T1.Date = #PDate AND T2.Date = #NDate
)
INSERT INTO YourTable (Date,Type,Quantity)
SELECT #NDate,Type1,Q1
WHERE X.Type2 IS NULL
SET #PDate = #NDate
SET #NDate = NULL -- If next result wasnt found this stays null for while condition
SET #NDate = SELECT TOP 1 Date FROM YourTable WHERE Date>#PDate
END
I think this is the way that may work and I wish so
( if there is any syntax or ... mistakes its because I didnt have SSMS installed to test. Sorry)
try this :
declare #date date
and for initiate #date you can use select #date=max(date) from table1 or pass static value set #date='02/01/2019'
and then find input
select input,max(date) as MaxDate into #temp
from table1
where input not in (select input from table1 where date=#date )
group by input
then :
select t.* from Table1 t join #temp on Table1.input=#temp.Input and Table1.date=#temp.MaxDate
OK, after the goal posts are settled, this is one method. Note that this solution builds both a Types and Dates dataset. Really the Types dataset should already exist somewhere in your database, and you should create a Calendar Table if you're going to be doing this type of work often.
Any way, I've left comments in the code for you. I've assumed you're using SQL Server 2012+, as 2008 is literally about to run out of support.
CREATE TABLE dbo.MyTable (ID int IDENTITY(1,1),
[date] date,
[type] varchar(10),
Quantity int);
INSERT INTO dbo.MyTable
SELECT CONVERT(date,[date],103),
RTRIM([Type]),
Quantity
FROM (VALUES('29/04/2019','APPLE ',2),
('29/04/2019','Banana',15),
('29/04/2019','Mango ',100),
('29/04/2019','Grapes',50),
('29/04/2019','Fish ',80),
('30/04/2019','APPLE ',4),
('30/04/2019','Grapes',100),
('30/04/2019','Fish ',90),
('01/05/2019','APPLE ',6),
('01/05/2019','Banana',30),
('01/05/2019','Grapes',150),
('01/05/2019','Fish ',100),
('02/05/2019','Mango ',200),
('02/05/2019','Grapes',200),
('02/05/2019','Fish ',110),
('03/05/2019','APPLE ',8),
('03/05/2019','Banana',45),
('03/05/2019','Mango ',300),
('04/05/2019','APPLE ',10),
('04/05/2019','Grapes',300),
('04/05/2019','Fish ',120),
('05/05/2019','APPLE ',12),
('05/05/2019','Fish ',130)) V([date],[Type],Quantity);
GO
--SELECT *
--FROM dbo.MyTable;
GO
--Create a calendar table
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 days shuld be enough
Dates AS(
SELECT DATEADD(DAY, T.I, MIN(MT.[date])) AS [Date]
FROM Tally T
CROSS JOIN dbo.MyTable MT
GROUP BY T.I
HAVING DATEADD(DAY, T.I, MIN(MT.[date])) <= MAX([Date])),
--Get Types
Types AS (
SELECT DISTINCT [Type]
FROM dbo.MyTable MT),
--Create islands
Grps AS(
SELECT MT.ID,
D.[Date],
T.[Type],
MT.Quantity,
COUNT(MT.Quantity) OVER (PARTITION BY T.[Type] ORDER BY D.[date]
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Grp
FROM Dates D
CROSS JOIN Types T
LEFT JOIN dbo.MyTable MT ON D.[Date] = MT.[date]
AND T.[type] = MT.[type])
SELECT G.ID AS ID,
ROW_NUMBER() OVER (ORDER BY G.[Date], G.[Type]) AS RN,
G.[Date],
G.[Type],
MAX(G.Quantity) OVER (PARTITION BY G.[Type], G.Grp) AS Quantity
FROM Grps G
ORDER BY G.[Date],
G.[Type];
GO
DROP TABLE dbo.MyTable;
db<>fiddle
I think using cursor is a good option to insert your missing entries in the table. By cursor you will be able to check date wise missing types and insert them with the previous quantity.
You can also use this following script to find the missing records in your table. To create the script I consider the table name = 'add_missing_records'
SELECT AA.date AS [Date],
AA.type AS [Type],
BB.quantity AS [Original Quantity] ,
CASE
WHEN BB.quantity IS NULL THEN
(
SELECT quantity
FROM add_missing_records C
WHERE C.date = (
SELECT MAX([date])
FROM add_missing_records B
WHERE B.date < AA.date
AND B.type = AA.type
)
AND C.type = AA.type
)
ELSE BB.quantity
END AS [New Quantuty]
FROM (
SELECT date,type
FROM (
SELECT DISTINCT 'A' AS common,date
FROM add_missing_records
)A
FULL JOIN (
SELECT DISTINCT 'A' as common, type
FROM add_missing_records
)B
ON a.common = b.common
) AA
LEFT JOIN add_missing_records BB
ON AA.date = BB.date
AND AA.type = BB.type
WHERE BB.quantity IS NULL
ORDER BY 1,2

Please advise my the stored procedure which is group by and total which different criteria

I have answered one of the interview questions as below.
There are two tables (employee and Department).
Show report No. of people(count) and total salary where IT Dept. salary from 250 to 500 and Sales Dept. salary from 250 to 1000 and Marketing Dept. salary from 250 to 1500.
Sample expected result below
Marketing 0 0.00
Information Technology 1 250.00
Sales 2 1200.00
Employee table
EmpID EmpName DeptID Salary
1 Mike 1 1000.00
2 Paul 1 1500.00
3 John 1 2000.00
4 Joe 2 500.00
5 Kim 3 2000.00
6 Lim 3 2500.00
7 Sam 2 700.00
8 Mario 1 250.00
Department table
DeptID DeptCode DeptName
1 IT Information Technology
2 ST Sales
3 MT Marketing
My Answer:
ALTER PROCEDURE [dbo].[TheseAndThat]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT dd.DeptName, ISNULL(TT.c,0) AS StaffCount , ISNULL(TT.s,0) AS TotalSalary FROM [dbo].[Department] dd
LEFT JOIN
(
SELECT d.DeptCode AS dcode, COUNT(*) as c, SUM(e.Salary) as s FROM [dbo].[Employee] e
JOIN [dbo].[Department] d
ON e.DeptID = d.DeptID
WHERE e.Salary between 250 and 500 AND d.DeptID = 1
GROUP BY e.DeptID, d.DeptCode
UNION
SELECT d.DeptCode AS dcode, COUNT(*) as c, SUM(e.Salary) as s FROM [dbo].[Employee] e
JOIN [dbo].[Department] d
ON e.DeptID = d.DeptID
WHERE e.Salary between 250 and 1000 AND d.DeptID = 2
GROUP BY e.DeptID, d.DeptCode
UNION
SELECT d.DeptCode AS dcode, COUNT(*) as c, SUM(e.Salary) as s FROM [dbo].[Employee] e
JOIN [dbo].[Department] d
ON e.DeptID = d.DeptID
WHERE e.Salary between 250 and 1500 AND d.DeptID = 3
GROUP BY e.DeptID, d.DeptCode
) TT
ON dd.DeptCode = TT.dcode
ORDER BY TT.c
END
I'm not sure my answer is correct. However, the result seems to be ok.
Please advise.
If I was you I will go this this query (only 1 time scan to employee table)
SELECT d.DeptName, ISNULL(e.NoEmp,0) AS NoEmp, ISNULL(SumSalary,0) AS SumSalary
FROM [dbo].[Department] AS d
LEFT JOIN (
SELECT DeptID, COUNT(EmpID) As NoEmp, SUM (Salary) AS SumSalary
FROM [dbo].[Employee]
WHERE Salary BETWEEN 250 AND CASE WHEN DeptID = 1 THEN 500
WHEN DeptID = 2 THEN 1000
WHEN DeptID = 3 THEN 1500
END
GROUP BY DeptID) AS e ON d.DeptID = e.DeptID
WHERE d.DeptID IN(1,2,3)
First, the code to setup temp tables:
declare #employees table
(
EmpID int,
EmpName varchar(100),
DeptID int,
Salary decimal
)
declare #departament table
(
DeptID int,
DeptCode char(2),
DeptName varchar(100)
)
insert into #employees values (1,'Mike',1,1000.00)
insert into #employees values (2,'Paul',1,1500.00)
insert into #employees values (3,'John',1,2000.00)
insert into #employees values (4,'Joe',2,500.00)
insert into #employees values (5,'Kim',3,2000.00)
insert into #employees values (6,'Lim',3,2500.00)
insert into #employees values (7,'Sam',2,700.00)
insert into #employees values (8,'Mario',1,250.00)
insert into #departament values (1, 'IT', 'Information Technology')
insert into #departament values (2, 'ST', 'Sales')
insert into #departament values (3, 'MT', 'Marketing')
Now, the report:
select DeptName, COALESCE(d2.DeptID, 0), COALESCE(Salaries,0) from #departament d2
left join
(
select COUNT(*) as DeptID, SUM(Salary) as Salaries from #departament d
inner join #employees e on d.DeptID = e.DeptID
where
(d.DeptID = 1 and e.Salary between 250 and 500)
or
(d.DeptID = 2 and e.Salary between 250 and 1000)
or
(d.DeptID = 3 and e.Salary between 250 and 1500)
group by d.DeptID) as sums on sums.DeptID = d2.DeptID
An alternative (uses the same temp tables as #GustavoF answer):
DECLARE #Input TABLE( DeptID INT, SalaryRangeMin decimal, SalaryRangeMax decimal )
INSERT INTO #Input
VALUES
( 1, 250, 500),
( 2 ,250 ,1000 ),
( 3 ,250 , 1500 )
SELECT D.DeptName, COUNT(EmpID) as EmployeeCount, ISNULL( SUM( e.Salary ), 0.0 ) as TotalSalary
FROM #Input AS I
INNER JOIN #departament AS D ON I.DeptID = D.DeptID
LEFT JOIN #Employees AS E ON I.DeptID = E.DeptID AND E.Salary BETWEEN I.SalaryRangeMin AND I.SalaryRangeMax
GROUP BY E.DeptID, D.DeptCode, D.DeptName
ORDER BY TotalSalary ASC
Output:
DeptName EmployeeCount TotalSalary
--------------------------- ------------- -------------
Marketing 0 0
Information Technology 1 250
Sales 2 1200

Count users by create_timestamp and last login date

I want to perform a year by year count of users based upon their create_timestamp and their last_login date.
USER create_timestamp Last_login
10 2009-06-18 20161029
11 2010-07-01 20110101
12 2011-10-01 20150101
13 2012-12-01 20161101
Year Count
2009 1
2010 2
2011 3
2012 3
2013 3
2014 3
2015 3
2016 2
Would I be looking at using sum and case statements?
Try to create the xref table like below,create it as permanent table(i have used here temp table) and then join with your table like below
create table #xref(yearofemp int)
insert into #xref values(2009)
insert into #xref values(2010)
insert into #xref values(2011)
insert into #xref values(2012)
insert into #xref values(2013)
insert into #xref values(2014)
insert into #xref values(2015)
insert into #xref values(2016)
create table #emp(userid int,create_timestamp datetime,Last_login datetime)
insert into #emp values(10,'2009-06-18','20161029')
insert into #emp values(11,'2010-07-01','20110101')
insert into #emp values(12,'2011-10-01','20150101')
insert into #emp values(13,'2012-12-01','20161101')
select
a.yearofemp as Year_No
,COUNT(a.userid) as Count_of_emp
from
(
select
#emp.userid
,#xref.yearofemp
from #emp
inner join #xref
on yearofemp between year(#emp.create_timestamp )
and year(#emp.Last_login)
)a
group by a.yearofemp
order by a.yearofemp
And if you have index on create_timestamp and Last_login, then this query is able to use it.
create table #years(years datetime not null)
insert into #years
values
('2009-01-01'),
('2010-01-01'),
('2011-01-01'),
('2012-01-01'),
('2013-01-01'),
('2014-01-01'),
('2015-01-01'),
('2016-01-01')
create table #data(
userid int,
create_timestamp datetime,
Last_login datetime
)
insert into #data
values
(10,'2009-06-18','20161029'),
(11,'2010-07-01','20110101'),
(12,'2011-10-01','20150101'),
(13,'2012-12-01','20161101'),
select
year(y.years) as [Year],
ca.[Count]
from #years y
outer apply (
select
count(*) as [Count]
from #data d
where y.years between d.create_timestamp and d.Last_login
) ca

Convert rows to columns

I have the follwoing structure:
Emp PayDate Amount
1 11/23/2010 500
1 11/25/2010 -900
1 11/28/2010 1000
1 11/29/2010 2000
2 11/25/2010 2000
3 11/28/2010 -3000
2 11/28/2010 4000
3 11/29/2010 -5000
I need to get the following result if emp 1 is selected (top 3 dates and their corresponding vals - if they exist - 4th row is always ignored)
PayDate1 Amount1 Paydate2 Amount2 Paydate3 Amount3
11/23/2010 500 11/25/2010 -900 11/28/2010 1000
I need to get the following result if emp 2 is selected
Paydate1 Amount1 Paydate2 Amount2 Paydate3 Amount3
11/25/2010 2000 11/28/2010 4000 NULL NULL
I need to get the following result if emp 3 is selected
Paydate1 Amount1 Paydate2 Amount2 Paydate3 Amount3
11/28/2010 -3000 11/29/2010 -5000
To get the respective data in rows I can run the following query:
select top 3 Paydate, Amount from Table where Emp = #Emp
But how do I get result in a pivoted fashion?
There's an excellent article on Pivots with SQL Server 2005+ here.
CREATE TABLE dbo.Table1
(
Emp int,
PayDate datetime,
Amount int
)
GO
INSERT INTO dbo.Table1 VALUES (1, '11/23/2010',500)
INSERT INTO dbo.Table1 VALUES (1, '11/25/2010',-900)
INSERT INTO dbo.Table1 VALUES (1, '11/28/2010',1000)
INSERT INTO dbo.Table1 VALUES (1, '11/29/2010',2000)
INSERT INTO dbo.Table1 VALUES (2, '11/25/2010',2000)
INSERT INTO dbo.Table1 VALUES (3, '11/28/2010',-3000)
INSERT INTO dbo.Table1 VALUES (2, '11/28/2010',4000)
INSERT INTO dbo.Table1 VALUES (3, '11/29/2010',-5000)
;WITH cte AS
(SELECT Emp, PayDate, Amount, PayDateRowNumber
FROM
(SELECT Emp,
PayDate,
Amount,
ROW_NUMBER() OVER (PARTITION BY Emp ORDER BY PayDate) AS PayDateRowNumber
FROM Table1) AS RankedTable1
WHERE PayDateRowNumber < 4)
SELECT c1.Emp AS Emp, c1.PayDate AS PayDate1
,c1.Amount AS Amount1, c2.PayDate AS PayDate2
,c2.Amount AS Amount2, c3.PayDate AS PayDate3, c3.Amount AS Amount3
FROM cte c1
LEFT JOIN cte c2 ON c2.Emp = c1.Emp AND c2.PayDateRowNumber = 2
LEFT JOIN cte c3 ON c3.Emp = c2.Emp AND c3.PayDateRowNumber = 3
WHERE c1.PayDateRowNumber = 1
Output is:
Some caveats are that it won't aggregate amounts for the same employer/date (though can easily be changed). Also may want to change to review use of ROW_NUMBER() versus RANK() and DENSE_RANK() depending on your definition of "TOP 3"

Resources