attached image pointers regarding querying a table - sql

Please have a look at the image link to understand my scribbling in the question.
A table has users from different states of Australia who used different methods to approach the application.
This table has column for userids [id](1,2,3,4,5,6..14000), column approaches (a,b,c,d,e,f) and column states (wa,vic..)
Now I need to formulate a table which would have columns with column#1 as approaches and remaining column names with states names like westernaustralia, victoria, SA,queensland etc.
The approach 'a' row would have total no of people who used this approach in different states victoria 5 wa 0
And in the same way other 5 approaches would have number of people used the approach in different states(in columns).
(eg: approach 'b' row- vic 3 wa 1 sa2...etc)
Here's the link for the image please have a look at it .https://i.stack.imgur.com/DldhT.png

you can use a PIVOT statement like below.
create table data (id int, [state] nvarchar(100), approaches nvarchar(10));
insert into data values
(1,'nsw','a'),
(2,'','b'),
(3,'wa','c'),
(4,'qld','d');
select
approaches,
[New South Wales]=[nsw],
[Western Australia]=[wa],
[Queensland]=[qld],
[Victoria]=[vic],
[South Australia]=[sa],
[not available]
from
(
select
id,
case
when [state] ='' then 'not available'
else [state]
end as [state],
approaches
from data
)src
pivot
(
count(id) for [state] in ([nsw],[wa],[qld],[vic],[sa],[not available])
)p
see working demo

Related

SQL combine 2 rows into 1 row then delete 1

I'm trying to complete an SQL query homework question and cannot figure out how to add 2 rows together from the same table, with the intention of deleting one after they are combined.
I have a table name 'country', in it, I have 241 rows of data with columns.
name region area population GDP
------------------------------------------------------------------------
Hong Kong Southeast Asia 1040 5542869 136100000000
China Asia 9596960 1203097268 2978800000000
Expected output:
name region area population GDP
-------------------------------------------------------------------
Hong Kong Southeast Asia 1040 5542869 136100000000
China Asia 9598000 1208640137 3114900000000
The goal is to keep the name of the row as "China" and the region as "Asia" but adding the numeric values from the "Hong Kong" row to the "China" row for the columns (area, population, and GDP).
I have tried UNION and MERGE but I'm not familiar with using them and couldn't get it to work.
I feel like it has to be something like the SQL query below:
update country
set area = area.HongKong + area.China
where name = 'China';
but I don't know the proper way to reference a specific row.
Ah yes, homework. I remember those days.
Here is some code to help out -
--create a temp table to hold sample data
select
*
into #country
from
(
values
('Hong Kong', 'Southeast Asia', 1040, 5542869, 136100000000),
('China', 'Asia', 9596960, 1203097268, 2978800000000),
('USA', 'North America', 1, 10, 100) --some other row in table
) d ([name], region, area, population, gdp);
select * from #country;
Here is what the data looks like in this table:
--update statement
with
Totals as
(
select
count(1) rows, --should be 2
sum(area) areaTotal,
sum(population) populationTotal,
sum(gdp) gdpTotal
from #country
where [name] in ('Hong Kong', 'China') --this filter may be insufficient; it would be better to select by a primary key such as a rowID but the table does not have one
)
update c
set c.area = t.areaTotal,
c.population = t.populationTotal,
c.gdp = t.gdpTotal
from #country c
inner join totals t
on c.[name] = 'China';
Here is what the data looks like after the update:
There are a few noteworthy things here:
The code above the update statement, with Totals as (..., is called a common table expression (also abbreviated as CTE). It is being used here to contain the query that calculates the totals needed to perform the update. A CTE is one approach to creating an intermediate data set. Alternative approaches to this include: creating a temp table or using a derived table.
To see the results of the query within the CTE, those lines of code can be highlighted in your editor and executed against the database.
The original post said there are 241 rows of data in the country table. This means it is important to have a reliable filter in the query that calculates the totals so the correct rows for summing are isolated. The preferred way to filter the rows is to use a primary key, such as a rowID. Since this table does not have a primary key column, I made a guess and used the [name] column.
The purpose of count(1) rows in the CTE is to make sure only 2 rows are being summed. If this number comes back as anything other than 2, it means there is a problem with the filter and the where clause needs to be modified. The number of rows will only be visible when you do #2 above.
Now the Hong Kong row needs to be cleaned up:
--delete old row
delete from #country where [name] = 'Hong Kong';
This is what the data looks like now:
Again, it would be preferable to use a primary key column in the where clause instead of the [name] column to be certain that the correct row is being deleted.

Can I get some help me in writing a SQL query for searching multiple words in a table column

I am trying to write a query that searches a column of a table and returns the count with an alias name for multiple words.
select
count(STREET_ADDRESS) AS MELBOURNE
from
CUSTOMERS
where
STREET_ADDRESS like '%MELBOURNE%'
I am trying to do this for multiple cities in one query like Melbourne, Sydney, Auckland etc.
Try This,SELECT COUNT(*) FROM CUSTOMERS WHERE STREET_ADDRESS IN ('MANGERE','AVONDALE')GROUP BY STREET_ADDRESS
Keep in mind that the number of columns in the select is fixed. Maybe i missunderstood but you want to input a list of cities and have the output contain as many columns as input's you gave?
If not (fixed Nb cities):
Suggestion: Add conditions to the query (to be honest, since using wildcards no really perf enhancement, you should think about adding a "city" column otherwise if the table gets too big this query will become very slow)
SELECT
SUM(CASE WHEN STREET_ADDRESS LIKE '%MANGERE%' THEN 1 ELSE 0 END) AS MANGERE_COUNT,
SUM(CASE WHEN STREET_ADDRESS LIKE '%AVONDALE%' THEN 1 ELSE 0 END) AS AVONDALE_COUNT
FROM CUSTOMERS
WHERE
STREET_ADDRESS like '%MANGERE%'
OR
STREET_ADDRESS like '%AVONDALE%'
If that is the case:
You will need to create dynamic SQL to transpose the output.
Hope it helps
Sérgio
Have a derived table where you using a case expression returns the city name from each street_address. Then do GROUP BY on its result to count:
select count(*), city
from
(
select case when upper(STREET_ADDRESS) like '%MELBOURNE%' then 'Melbourne'
when upper(STREET_ADDRESS) like '%SYDNEY%' then 'Sydney'
when upper(STREET_ADDRESS) like '%AUCKLAND%' then 'Auckland'
end as city
from CUSTOMERS
) dt
group by city
Note: the UPPER() parts aren't needed if a case insensitive collation is used.

SQL using where contains to return rows based on the content of another table

I need some help:
I have a table called Countries, which has a column named Town and a column named Country.
Then I have table named Stores, which has several columns (it is a very badly set up table) but the ones that are important are the columns named Address1 and Address2.
I want to return all of the rows in Stores where Address1 and Address2 contains the towns in the Countries table.
I have a feeling this is a simple solution but I just can't see it.
It would help if maybe you could use WHERE CONTAINS but in your parameters search in another table's column?
e.g.
SELECT *
FROM Stores
WHERE CONTAINS (Address1, 'Select Towns from Countries')
but obviously that is not possible, is there a simple solution for this?
You're close
SELECT * FROM Stores s
WHERE EXISTS (
SELECT * FROM Countries
WHERE CONTAINS(s.Address1, Town) OR CONTAINS(s.Address2, Town)
)
This would be my first attempt:
select * from stores s
where
exists
(
select 1 from countries c
where s.Address1 + s.Address2 like '%'+c.Town+'%'
)
Edit: Ooops just saw that you want the 'CONTAINS' clause. Then take Paul's solution

Concatenate one field after GROUP BY

This question have been asked many times in SO but none of the answers is satisfying to my situation.
Question 1
Question 2
Question 3
Question 4
I am dealing with a DataObjectVersions table that contains multiple versions for around 1.2 million unique objects (and increasing). I need to concatenate changes from a specific field for each unique object.
Right now I am using the solution with the XML Path presented in Q3 but running such a query on this table is a total performance disaster. SQL Server started to retun Data after 19mn. Knowing that this data will be than joined twice, you can imagine the impact.
I am looking for the most efficient scalability-aware way to concatenate the values of the same fields of different rows grouped by an other field (which is not of course a key). To be more precise, this is used within a view in a Datawarehouse.
EDIT:
I tried to simplify the description but here is a complete overview
I have multiple tables with the following columns
[ID]
[CreatedTime]
[CreatedBy]
[DeletedTime]
[DeletedBy]
[ResourceId]
[AccountId]
[Type]
A view is used to return the union of all records from all tables, which will still return the same columns (described in my questions by the versions table). [ResourceId] and [AccountId] are a unique composite identifier of an object (Group membership, System account, etc.. a resource assignment specifically). The [Type] is used to identify different levels (like Read/Write/Execute in the case of a file assignment)
All other fields contain the same values (in different tables) for different unique objects. I need to get the objects and concatenate the values of the [Type] column. All the row are processed afterward and the ([ResourceId],[AccountId]) combination must be unique (not the case when different types exists).
EDIT 2:
I am using this function:
CREATE FUNCTION [dbo].[GetUniqueType]
(
#ResourceId as uniqueidentifier,
#Account as uniqueidentifier
)
RETURNS nvarchar(100)
AS
BEGIN
return STUFF((select ',' + raType.Type from vwAllAssignments raType where raType.AccountId = #Account and raType.ResourceId = #ResourceId and raType.DeletedBy is null for xml path('')), 1,1,'')
END
GO
vwAllAssignments is the view returning the union of all tables rows.
Finally I am selecting
SELECT [CreatedTime]
,[DeletedTime]
,[DeletedBy]
,[ResourceId]
,[AccountId]
,dbo.GetUniqueType([ResourceId],[AccountId]) AS [Type]
FROM vwAllAssignments
GROUP BY [ResourceId], [AccountId], [CreatedTime], [DeletedTime], [DeletedBy]
Try this:
SELECT [CreatedTime]
,[DeletedTime]
,[DeletedBy]
,[ResourceId]
,[AccountId]
,STUFF((select ',' + raType.Type
from vwAllAssignments raType
where raType.AccountId = vwAllAssignments.AccountId and
raType.ResourceId = vwAllAssignments.ResourceId and
raType.DeletedBy is null
for xml path('')), 1,1,'') AS [Type]
FROM vwAllAssignments
GROUP BY [ResourceId], [AccountId], [CreatedTime], [DeletedTime], [DeletedBy]
And an index like this should be helpful.
create index IX_vwAllAssignments on vwAllAssignments(AccountId, ResourceId, DeletedBy) include(Type)

Insert blank row between groups of rows and sorted by ID in sql

I have a table which has the following columns and values
ID TYPE NAME
1 MAJOR RAM
2 MAJOR SHYAM
3 MAJOR BHOLE
4 MAJOR NATHA
5 MINOR JOHN
6 MINOR SMITH
My requirement is to right a stored procedure (or SQL query) which would return the same resultset except that there will be blank line after the TYPE changes from one type to another type (major, minor).
MAJOR RAM
MAJOR SHYAM
MAJOR BHOLE
MAJOR NATHA
MINOR JOHN
MINOR SMITH
While i use this query for adding blank line but it is not sorted by basis of ID
select TYPE, NAME from (
select
TYPE as P1,
1 as P2,
ID,
TYPE,
NAME
from EMP
union all
select distinct
TYPE,
2,
'',
'',
N''
from EMP
) Report
order by P1, P2
go
How i sort data by ID
Thanks in advance
Yes, yes, don't do this, but here's the query to do it, assuming SQL Server 2008 R2. Other versions/rdbms you can achieve same functionality by writing two separate queries unioned together.
Query
; WITH DEMO (id, [type], [name]) AS
(
SELECT 1,'MAJOR','RAM'
UNION ALL SELECT 2,'MAJOR','SHYAM'
UNION ALL SELECT 3,'MAJOR','BHOLE'
UNION ALL SELECT 4,'MAJOR','NATHA'
UNION ALL SELECT 5,'MINOR','JOHN'
UNION ALL SELECT 6,'MINOR','SMITH'
)
, GROUPED AS
(
SELECT
D.[type]
, D.[name]
, ROW_NUMBER() OVER (ORDER BY D.[type] ASC, D.[name] DESC) AS order_key
FROM
DEMO D
GROUP BY
--grouping sets introduced with SQL Server 2008 R2
-- http://msdn.microsoft.com/en-us/library/bb510427.aspx
GROUPING SETS
(
[type]
, ([type], [name])
)
)
SELECT
CASE WHEN G.[name] IS NULL THEN NULL ELSE G.[type] END AS [type]
, G.[name]
FROM
GROUPED G
ORDER BY
G.order_key
Results
If you don't like the nulls, use coalsece to make empty strings
type name
MAJOR SHYAM
MAJOR RAM
MAJOR NATHA
MAJOR BHOLE
NULL NULL
MINOR SMITH
MINOR JOHN
NULL NULL
I agree with billinkc.
In a sequential mind, like mine, it can occur different.
The approach is to use a cursor and insert the records into a temp table.
This table can have a column, INT type, lets say it is called "POSITION" which increments with every insert.
Check for ID changes, and add the empty row everytime it does.
Finally make the SELECT order by "POSITION".
My context was:
An interface that dinamically adjust to what the user needs, one of the screens shows a payment table, grouped by provider with the approach early mentioned.
I decided to manage this from database and skip maintainance for the screen at client side because every provider has different payment terms.
Hope this helps, and lets keep an open mind, avoid saying "don't do this" or "this is not what SQL was designed for"