Not able to add row wise data in column form - sql

EmpID (Primary Key) Sale Items Paid
ABC chair Yes
WXY chair Under Review
PER Laptop Yes
ABC Chair Yes
Now i want to create another table where i want to insert data Like below
Emp ID Chair Laptop
ABC 2 0
WXY 1 0
My query to insert is
Select Emp Id from EMP,count(sales_item) as chair where Sales_Item = 'chair'
it is working now how to add Laptop (3rd Column ) . can you please suggest

You would use conditional aggregation:
Select EmpId,
sum(case when sales_item = 'chair' then 1 else 0 end) as chairs,
sum(case when sales_item = 'laptop' then 1 else 0 end) as laptops
from EMP
group by EmpId;
There is no reason to store this in a separate table. If you like, you can create a view. Then when you access the view, you know the data is up-to-date.

You could use pivot for the expected result:
DECLARE #t TABLE(
EmpID varchar(3)
,SaleItems varchar(10)
,Paid varchar(20)
)
INSERT INTO #t VALUES
('ABC', 'chair', 'Yes')
,('WXY', 'chair', 'Under Review')
,('PER', 'Laptop', 'Yes')
,('ABC', 'Chair', 'Yes')
SELECT piv.EmpID, ISNULL(piv.chair, 0) AS chair, ISNULL(piv.Laptop, 0) AS Laptop
FROM(
SELECT EmpID, SaleItems, 1 cnt
FROM #t
) x
PIVOT
(
SUM(cnt)
FOR SaleItems IN ([chair], [Laptop])
) piv

Related

Each Column in Separate Row

How can I display each column in separate row and at the end add additional field.
For example I have this result:
ID ArticleName Brend1 Brend2 Brend3
== =========== ======== ======== ========
1 TestArticle 10001 20002 30003
I want to achieve this:
ID ArticleName BrandNo BrandName
== =========== ======= =========
1 TestArticle 10001 if column name = Brand1 Then Nike
1 TestArticle 20002 if column name = Brand2 Then Adidas
1 TestArticle 30003 if column name = Brand3 Then Mercedes
I can show each column in separate row, but how can I add additional column to the end of the result BrandName
Here is what I've done:
DECLARE #temTable TABLE
(
Id INT,
ArticleName VARCHAR(20),
Brand1 VARCHAR(20),
Brand2 VARCHAR(20),
Brand3 VARCHAR(20)
);
INSERT INTO #temTable
(
Id,
ArticleName,
Brand1,
Brand2,
Brand3
)
VALUES
(1, 'TestArticle', '10001', '20002', '30003');
SELECT Id,
ArticleName,
b.*
FROM #temTable a
CROSS APPLY
(
VALUES
(Brand1),
(Brand2),
(Brand3)
) b (Brand)
WHERE b.Brand IS NOT NULL;
You could use CROSS APPLY as
SELECT Id, ArticleName, Br BrandNo, Val BrandName
FROM #TemTable TT
CROSS APPLY(
VALUES
(Brand1, 'Nike'),
(Brand2, 'Adidas'),
(Brand3, 'Mercedes')
) T(Br, Val)
db-fiddle
I assume the brand is stored in another table, so you just need to add another column in your VALUES operator, and then join to the Brand Table:
SELECT Id,
ArticleName,
V.Brand
FROM #temTable a
CROSS APPLY (VALUES (1,Brand1),
(2,Brand2),
(3,Brand3)) V (BrandID,Brand)
JOIN dbo.Brand B ON V.BrandID = B.BrandID
WHERE V.Brand IS NOT NULL;
You can use UNPIVOT to achieve this. You can use either a case statement or another table variable to switch column names with brand names, I would prefer a table variable with a join it would make adding new column a bit easier.
DECLARE #d TABLE (ColNames VARCHAR(128) , BrandName VARCHAR(100))
INSERT INTO #d VALUES ('Brand1', 'Nike'),('Brand2', 'Adidas'),('Brand3', 'Mercedes')
SELECT up.Id
, up.ArticleName
, up.BrandNo
, d.BrandName
FROM #temTable
UNPIVOT (BrandNo FOR ColNames IN (Brand1,Brand2,Brand3)) up
INNER JOIN #d d ON d.ColNames = up.ColNames

Get the sum of details table

I need to retrieve a master record together the sum of its details. Here are the definitions of two tables:
Master table (Master)
ID
Name
Example record:
10 Product
Details table (Details)
master_id
type (values can only be red or blue)
quantity
Example records:
10 red 2
10 red 5
10 red 6
10 blue 7
10 blue 9
I need to have such results:
10 Product 13 (sum for red) 16 (sum for blue)
The database is SQL Server 2017. How can I write a SINGLE query without using a stored procedure?
---UPDATE---
Based on the input from Venkataraman R, here is the solution:
SELECT m.id, m.name ,
SUM(CASE when type='red' then quantity end) as redsum,
SUM(CASE when type='blue' then quantity end) as bluesum
from mydetails as t
inner join mymaster as m
on m.id = t.master_id
GROUP BY m.id, m.name
You can use CONCAT function with group by to get results as single statement.
DECLARE #table table(master_id int, typev varchar(10), quantity int)
DECLARE #master table(id int, name varchar(50))
insert into #master values(10, 'Product10')
insert into #table values
(10,'red', 2),
(10,'red', 5),
(10,'red', 6),
(10,'blue', 7),
(10,'blue', 9);
SELECT m.name ,
SUM(CASE when typev='red' then quantity end) as redsum,
SUM(CASE when typev='blue' then quantity end) as bluesum
from #table as t
inner join #master as m
on m.id = t.master_id
GROUP BY m.name
+-----------+--------+---------+
| name | redsum | bluesum |
+-----------+--------+---------+
| Product10 | 13 | 16 |
+-----------+--------+---------+
If I get you correctly then you are looking for pivot, in that case you can use case expressions as following
select
master_id,
sum(case when type = 'red' then quantity end) as sum_of_red,
sum(case when type = 'blue' then quantity end) as sum_of_blue
from yourTable
group by
master_id
If you simply wants total quantity by type then use the following
select
master_id,
type,
sum(quantity) as total_quantity
from yourTable
group by
master_id,
type
Just use a group by
Select master_id, type, sum(quantity)
From details group by master_id, type
And use pivot to show each product in one line
With data_cte as
(Select master_id, type, sum(quantity)
From details group by master_id, type)
Select * from data_cte pivot (
For type in ('red', 'black'))

How to do pivoting on this layered data

Hi I have sample data
declare #emp table(id int identity(1,1),E_Name varchar(20),E_company varchar(20),Emp_Val VARCHAR(10))
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Rahim','WELLS','A')
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Jag','collebra',NULL)
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Vasu','nunet',NULL)
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Kiran','crystal',NULL)
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Sajan','tiato',NULL)
insert into #emp(E_Name,E_company,Emp_Val)VALUES('RAM','WELLS','A')
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Srinu','Cognizant','B')
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Raju','Cognizant','B')
Sample data :
id E_Name E_company Emp_Val
1 Rahim WELLS A
2 Jag collebra NULL
3 Vasu nunet NULL
4 Kiran crystal NULL
5 Sajan tiato NULL
6 RAM WELLS A
7 Srinu Cognizant B
8 Raju Cognizant B
script :
SELECT [WELLS],[Cognizant],[NULL] from (
select E_Name,E_company,Emp_Val from #emp)T
PIVOT (MAX(E_Name)FOR E_company IN([WELLS],[Cognizant],[NULL]))PVT
output :
WELLS Cognizant NULL
Rahim Srinu collebra
RAM Raju tiato
NULL Srinu crystal
NULL NULL NUNET
You can use conditional aggregation:
select max(case when e_company = 'WELLS' then e_name end) as wells,
max(case when e_company = 'Cognizant' then e_name end) as cognizant,
max(case when e_company not in ('WELLS', 'Cognizant') then e_name end) as nulls
from (select e.*,
row_number() over (partition by (case when e_company in ('WELLS', 'Cognizant') then e_company end) order by id) as seqnum
from #emp e
) e
group by seqnum
order by seqnum;
Here is a db<>fiddle.
your mistake is in the last select statement, it should be like this:
SELECT *
from (
select * from #emp)T
PIVOT (MAX(Emp_Val)FOR E_company IN([WELLS],[Cognizant],[NULL]))PVT
order by 1
This approach uses a self join within the pivot to enumerate the companies with multiple employes and values. It then uses a right join back on to the table to enumerate the companies that do not have those employees. The difference in the output is that all of the null permutations are preserved. Other than that this should cover what you are looking for.
declare #emp table(id int identity(1,1),E_Name varchar(20),E_company
varchar(20),Emp_Val VARCHAR(10))
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Rahim','WELLS','A')
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Jag','collebra',NULL)
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Vasu','nunet',NULL)
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Kiran','crystal',NULL)
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Sajan','tiato',NULL)
insert into #emp(E_Name,E_company,Emp_Val)VALUES('RAM','WELLS','A')
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Srinu','Cognizant','B')
insert into #emp(E_Name,E_company,Emp_Val)VALUES('Raju','Cognizant','B')
select distinct WELLS, Cognizant,case E_Company when 'Wells' then NULL when
'Cognizant' then null else E_Company end as [NULL] from
(
SELECT [WELLS],[Cognizant],[collebra], [nunet], [crystal], [tiato] from (
select e.E_Name,e2.E_name as E2_Name, e.E_company,e2.Emp_Val as Emp2_Val, e.Emp_Val
from #emp e inner join #emp e2 on e.id=e2.id)T
PIVOT (MAX(E_Name)FOR E_company IN([WELLS],[Cognizant],[collebra], [nunet],
[crystal], [tiato]))PVT) stagingtable
right join (select E_Company, E_Name from #emp) c on stagingtable.Cognizant=c.E_Name
or stagingtable.WELLS=c.E_Name
order by 1 desc, 2 desc, 3 desc;

SQL | View Column as Multiple Columns Based on Conditions

Newbie Postgresql (9.6.6) question here :)
I want to create a View that will split a single column into several columns, based on different conditions.
Example Table
Name Score Season
------- ------- --------
John 12 Fall
John 15 Winter
John 13 Spring
Sally 17 Fall
Sally 10 Winter
Sally 14 Spring
Henry 16 Fall
Henry 12 Winter
Henry 18 Spring
I want the View to dislay something that looks like this:
Name Fall Score Winter Score Spring Score
------- ------------ -------------- --------------
John 12 15 13
Sally 17 10 14
Henry 16 12 18
Where the "Score" field is broken out into several different columns, each one populated based on WHERE clause that references the "Season" field. I've looked into both Window Functions and CASE Statements for accomplishing this purpose, but haven't been successfully thus far.
Any help is greatly appreciated!
Selecting from the entire table while grouping over the Name and then conditionally SUMming over the Score column will work:
SELECT
"Name",
SUM(CASE WHEN "Season" = 'Fall' THEN "Score" ELSE 0 END) AS "Fall",
SUM(CASE WHEN "Season" = 'Winter' THEN "Score" ELSE 0 END) AS "Winter",
SUM(CASE WHEN "Season" = 'Spring' THEN "Score" ELSE 0 END) AS "Spring"
FROM "mytable"
GROUP BY "Name"
Whether or not you use SUM() is up to you and how your data looks. If you have one row per (Name, Season) pair then SUM() will work equally as well as MAX()
You need a pivot table:
On SQL server you can do something like this example (hope it's the same for postgress), in others versions of SQL exist the pivot relational operators, but I'm not sure if Pivot works on Postgres
Example:
CREATE TABLE #Table
(
Name nvarchar(400),
Score int,
Season nvarchar(400)
)
insert into #Table values ( 'John ',12,'Fall')
insert into #Table values ( 'John ',15,'Winter' )
insert into #Table values ( 'John ',13,'Spring' )
insert into #Table values ( 'Sally',17,'Fall ' )
insert into #Table values ( 'Sally',10,'Winter' )
insert into #Table values ( 'Sally',14,'Spring' )
insert into #Table values ( 'Henry',16,'Fall' )
insert into #Table values ( 'Henry',12,'Winter' )
insert into #Table values ( 'Henry',18,'Spring' )
select
c.Name
,sum(c.[Fall Score]) as [Fall Score]
,sum(c.[Winter Score]) as [Winter Score]
,sum(c.[Spring Score]) as [Spring Score]
from
(SELECT
t.name,
case
when t.Season = 'Fall' then t.Score
when t.Season = 'Winter' then 0
when t.Season = 'Spring' then 0
end as [Fall Score],
case
when t.Season = 'Fall' then 0
when t.Season = 'Winter' then t.Score
when t.Season = 'Spring' then 0
end as [Winter Score],
case
when t.Season = 'Fall' then 0
when t.Season = 'Winter' then 0
when t.Season = 'Spring' then t.Score
end as [Spring Score]
from #Table t
)as c
group by c.name

Query to exclude two or more records if they match a single value

I have a database table in which multiple customers can be assigned to multiple types. I am having trouble formulating a query that will exclude all customer records that match a certain type. For example:
ID CustomerName Type
=========================
111 John Smith TFS-A
111 John Smith PRO
111 John Smith RWAY
222 Jane Doe PRO
222 Jane Doe TFS-A
333 Richard Smalls PRO
444 Bob Rhoads PRO
555 Jacob Jones TFS-B
555 Jacob Jones TFS-A
What I want is to pull only those people who are marked PRO but not marked TFS. If they are PRO and TFS, exclude them.
Any help is greatly appreciated.
You can get all 'PRO' customers and use NOT EXISTS clause to exclude the ones that are also 'TFS':
SELECT DISTINCT ID, CustomerName
FROM mytable AS t1
WHERE [Type] = 'PRO' AND NOT EXISTS (SELECT 1
FROM mytable AS t2
WHERE t1.ID = t2.ID AND [Type] LIKE 'TFS%')
SQL Fiddle Demo
solution using EXCEPT
WITH TestData
AS (
SELECT *
FROM (
VALUES ( 111, 'John Smith', 'TFS-A' )
, ( 111, 'John Smith', 'PRO' )
, ( 111, 'John Smith', 'RWAY' )
, ( 222, 'Jane Doe', 'PRO' )
, ( 222, 'Jane Doe', 'TFS-A' )
, ( 333, 'Richard Smalls', 'PRO' )
, ( 444, 'Bob Rhoads', 'PRO' )
, ( 555, 'Jacob Jones', 'TFS-B' )
, ( 555, 'Jacob Jones', 'TFS-A' ))
AS t (ID, CustomerName, [Type])
)
SELECT ID, CustomerName
FROM TestData
WHERE [Type] = 'PRO'
EXCEPT
SELECT ID, CustomerName
FROM TestData
WHERE [Type] LIKE 'TFS%'
output result
Select DISTINCT(Customername),ID
FROM tablename
WHERE NOT (ID IN (SELECT ID FROM tablename WHERE type='PRO')
AND ID IN (SELECT ID FROM tablename WHERE type='TFS'))
EDIT: now added working TFS clause
Get all customers that do not have TYPE PRO AND TFS for example
SQLFIDDLE:http://sqlfiddle.com/#!9/da4f9/2
Try This :
SELECT *
FROM table a
WHERE Type = 'PRO'
AND NOT EXISTS(SELECT 1
FROM table b
WHERE a.ID = b.ID
AND LEFT(Type, 3) = 'TFS')
I know this question has been answered, but mine answer is different. Everyone else solutions involves two queries which means what I call "double-dipping". You have to look access the same table twice. It's better to avoid this when possible for better performance. Check this out:
SELECT ID,
CustomerName,
MIN([type]) AS [Type] --doesn't matter if it's MIN or MAX
FROM yourTable
WHERE [Type] = 'PRO' --only load values that matter. Ignore RWAY
OR [Type] LIKE 'TFS-_' --notice I use a "_" instead of "%". That because "_" is a wildcard for a single character
--instead of wildcard looking for any number of characters because normally it's best to be as narrow as possible to be more efficient
GROUP BY ID,CustomerName
HAVING SUM(CASE
WHEN [Type] = 'Pro' --This is where it returns values that only have type PRO
THEN 9999
ELSE 1
END
) = 9999
So let me explain my funky HAVING logic. So as you can see it's a SUM() so and for PRO it's 9999 and TFS-_ it's 1. So when the sum is EXACTLY 9999, then it's good. Why I can't just do a COUNT(*) = 1 is because if a value has only one TFS and no pro, it would be returned, which of course would be incorrect.
Results:
ID CustomerName Type
----------- -------------- -----
444 Bob Rhoads PRO
333 Richard Smalls PRO