I have got a table which goes something like this:
State_id | County_id| City_id | Name | Additional_Name
-----------------------------------------------------------------
1 | 0 | 0 | California | State
1 | 1 | 0 | Los Angeles | County
1 | 1 | 1 | Los Angeles | City
1 | 2 | 0 | San Diego | County
1 | 2 | 1 | San Diego | City
2 | 0 | 0 | Texas | State
2 | 1 | 0 | Harris | County
2 | 1 | 1 | Houston | City
It goes on for 10,000 rows. What I'm trying to accomplish is to build a SELECT statement which will result in:
State | County | City
-------------------------------------------
California | Los Angeles | Los Angeles
California | San Diego | San Diego
Texas | Harris | Houston
As you can see i want to select every city and display it's state, and county. The state_id, county_id, city_id and Additonal_Name columns should be essential in solving this problem, but i have no idea how to use them.
This will get your data, using your current table structure:
SELECT t2.[Name] AS [State]
,t3.[Name] AS County
,t1.[Name] AS City
FROM MyTable t1
JOIN MyTable t2 -- get state
ON t2.State_id = t1.State_id
AND t2.County_id = 0
AND t2.City_id = 0
JOIN MyTable t3 -- get county
ON t3.County_id = t1.County_id
AND t3.State_id = t1.State_id
AND t3.City_id = 0
WHERE t1.City_id > 0 --(or use t1.Additional_Name = 'City'
But Really:
You should be normalizing your database into three separate tables:
City
State
County
This will make using your data, and writing queries - muchh simpler and readable.
The tables would look something like this:
State
ID Name
1 California
2 Texas
County
ID Name
1 Los Angeles
2 San Diego
3 Harris
City
ID StateID CountyID Name
1 1 1 Los Angeles
2 1 2 San Diego
3 2 3 Houston
Hopefully you can see how much easier that is to manage things. You can choose to add a StateID to the County table to normalize further. But I'll keep my answer short.
Select the same data from these new tables with a similar query:
SELECT state.[Name] AS [State]
,county.[Name] AS County
,city.[Name] AS City
FROM MyCity city
JOIN MyState state ON state.ID = city.StateID -- get state
JOIN MyCounty county ON county.ID = city.CountyID -- get county
Related
Let's say I have following (fictional) dataset
ID | Name | Location | LastUpdated
1 | Bill | Germany | 2017-01-02
2 | Bill | Germany | 2017-01-03
3 | Bill | Germany | 2017-01-04
4 | Bill | Germany | 2017-01-05
5 | Jack | U.K | 2017-01-02
6 | Jack | U.K | 2017-01-03
7 | Jack | U.K | 2017-01-04
8 | John | Japan | 2017-02-22
9 | John | Japan | 2017-02-23
10 | John | Japan | 2017-02-24
11 | John | Japan | 2017-02-25
With my dataset I want to remove all records where lastupdated equals 2017-01-03
I also want to remove all of John's records where lastupdated equal or is greater then 2017-02-24
I tried following SQL statement:
SELECT *
FROM Table
WHERE (LastUpdated <> '2017-01-03')
AND (Name <> 'John' AND LastUpdated >= '2017-02-24')
But this way, it only returns the records with a LastUpdated greater then 2017-02-24
It seems pretty basic, but I can't work it out. Any ideas?
You can transcript your requirements like this:
I want to remove all records where lastupdated equals 2017-01-03
This is correct from your attempt:
LastUpdated <> '2017-01-03'
I also want to remove all of John's records where lastupdated equal or
is greater then 2017-02-24
This one is a little trickier. Either the record we want to display isn't John's OR the record is John's AND the date has to be lower than 2017-02-24. This is expressed like the following:
(
Name <> 'John' OR
(Name = 'John' AND LastUpdated < '2017-02-24')
)
So the final expression would be:
SELECT *
FROM [Table]
WHERE
LastUpdated <> '2017-01-03' AND
(
Name <> 'John' OR
(Name = 'John' AND LastUpdated < '2017-02-24')
)
Also if name can hold NULL values, you might need another OR expression that checks for NULL:
(
Name <> 'John' OR
Name IS NULL OR
(Name = 'John' AND LastUpdated < '2017-02-24')
)
You can write it as a NOT condition to keep it simple:
WHERE NOT (
(lastupdated = 2017-01-03)
OR
(name = 'John' AND lastupdated >= '2017-02-24')
)
We have cars table.
It has marques:
Nissan
Toyota
BMW
We have cities:
New York
Los Angeles
Dallas
Table:
Id
Marque
CityId
It has all 250 000 cars for the 3 cities.
How do we show them grouped by city and count, but the cities are columns.
This is my query:
SELECT Count(veh.id) [Count],pd.District, vet.Name FROM Vehicles veh
INNER JOIN PostalDistricts pd on pd.Id = veh.PostalDistrictId
INNER JOIN VehicleMarqueId vet on vet.id = veh.VehicleMarqueId
GROUP BY pd.District, vet.Name
ORDER BY Count(veh.id) DESC, pd.District asc
But the result is:
+-------+-------------+--------+
| Count | City | Marque |
+-------+-------------+--------+
| 9547 | New York | Toyota |
| 3509 | Dallas | Toyota |
| 2608 | Los Angeles | Toyota |
| 2545 | New York | Nissan |
| 2107 | Dallas | Nissan |
| 1780 | Los Angeles | Nissan |
+-------+-------------+--------+
Expected is:
+-------------+--------+--------+
| City | Toyota | Nissan |
+-------------+--------+--------+
| Dallas | 3509 | 2107 |
| Los Angeles | 2608 | 1780 |
| New York | 9547 | 2545 |
+-------------+--------+--------+
You can use the pivot statement:
declare #tmp table ([count] int , City varchar(50), Marque nvarchar(50))
insert into #tmp values
(9547, 'New York', 'Toyota')
,(3509, 'Dallas', 'Toyota')
,(2608, 'Los Angeles', 'Toyota')
,(2545, 'New York', 'Nissan')
,(2107, 'Dallas', 'Nissan')
,(1780, 'Los Angeles', 'Nissan')
select * from #tmp
pivot
(
max([count])
for Marque in ([Toyota], [Nissan] )
) piv
Results:
But if you have more values in the Marque column you have to use dynamic TSQL to generate all the columns needed
i have 3 table with name city and state and project
city
id_city | name_city
1 | JED
2 | RYD
3 | DMM
state
column city_id foreign key with city.city_id
id_state | name_state | city_id
1 | JED 1 | 1(JED)
2 | RYD 1 | 2(RYD)
3 | RYD 2 | 2(RYD)
project
column state_from_city_id_table_state foreign key with state .city_id
id_project | city_id | state_from_city_id_table_state
1 | 1 | 1(JED)>> (JED1) question here
2 | 2 | 2(RYD)>> (RYD 1 or2) question here
now question is i selected city_id from project table ... like 1 and i just want see city_id from state table number 1 without number 2 in state_id from table project
like this JED > JED1 only i don't wanna see RYD1 and RYD2
SELECT ct.*, st.*, pr.* FROM `city` ct LEFT JOIN `state` st ON ct.`id_city` = st.`state_id` LEFT JOIN `project` pr ON ct.`id_city` = pr.`city_id`
Suppose I have a table tb such that
select * from tb
returns
ID | City | Country
1 | New York | US
2 | Chicago | US
3 | Boston | US
4 | Beijing | China
5 | Shanghai | China
6 | London | UK
What is the easiest way to write a query that can return the following result?
ID | City | Country | Count
1 | New York | US | 3
2 | Chicago | US | 3
3 | Boston | US | 3
4 | Beijing | China | 2
5 | Shanghai | China | 2
6 | London | UK | 1
The only solution I can think of is
with cte as (select country, count(1) as Count from tb group by country)
select tb.*, cte.Count from tb join cte on tb.Country = cte.Country
But I feel that is not succinct enough. I am wondering if there is anything like Duplicate_Number() over (partition by country) to do this.
Try this:
select *
,COUNT(*) OVER (PARTITION BY Country)
from tb
The OVER clause
Determines the partitioning and ordering of a rowset before the
associated window function is applied.
So, we are basically telling to COUNT the records, but to group the rows per COUNTRY.
Another approach to achieve the result :
select t1.*, t2.Country_Count from tb t1
join
(select country, count(country) Country_Count from tb group by country) t2
on t1.country=t2.country
order by t1.id
SQL HERE
Consider the following data model:
Customers
CustNum | First Name | Last Name
555 John Doe
CustomerAddresses
CustNum | ShippingAddress| Line1 | Line2 | City | State | Zip
555 | ADD1 | 333 A Dr. | Apt. 10 | Dallas | TX | 11345
555 | ADD2 | 111 B St. | NULL | Miami | FL | 22222
555 | WXYZ | 123 Main St. | NULL | Detroit | MI | 99998
OrderHeader
OrdNum | CustNum | OrderTotal | Line1 | Line2 | City | State| Zip
1000 | 555 | 67.00 | 123 Main St. | Ste 1 | Detroit | MI | 99998
OrderLine
OrderNo | Item | Price | ShippingAddress
1000 | X123 | 32.00 | ADD1
1000 | Y234 | 25.00 | ADD2
1000 | ZZZZ | 10.00 | NULL
There is a one-to-many relationship between Customers and CustomerAddresses.
Each OrderHeader, instead of a key relationship to the CustomerAddresses table, stores the address used for shipping in the Line1, Line2, City, State, and Zip fields.
In addition, it's possible to select a shipping address in the OrderLine table that overrides the address stored in the OrderHeader.
I'm trying to come up with a query to return data in the following format, to generate a list of mailing labels:
MailingLabels
OrderNo | Item | Line1 | Line2 | City | State | Zip
1000 | X123 | 333 A Dr. | Apt. 10 | Dallas | TX | 11345
1000 | Y234 | 111 B St. | NULL | Miami | FL | 22222
1000 | ZZZZ | 123 Main St. | NULL | Detroit | MI | 99998
Basically, if the OrderLine record has a ShippingAddress value, I want to return the corresponding address from the CustomerAddresses table.
If it is NULL, then I want to return the Line1, Line2, City, State, and Zip values stored in the OrderHeader table.
The problem is, when I use COALESCE or ISNULL, it's possible to return incorrect results. Here's my query:
SELECT OH.OrderNo, Item, ISNULL(CA.Line1, OH.Line1), ISNULL(CA.Line2, OH.Line2),
ISNULL(CA.City, OH.City), ISNULL(CA.State, OH.State), ISNULL(CA.Zip, OH.Zip)
FROM OrderHeader OH
JOIN OrderLine OL
ON OH.OrderNo = OL.OrderNo
LEFT JOIN CustomerAddress CA
ON OL.CustNum = CA.CustNum
AND OL.ShippingAddress = CA.ShippingAddress
With the above query, if the Line2 field is defined for the OrderHeader, but the ShippingAddress is defined in OrderLine, it's possible to return a mixed address for the Y234 item:
OrderNo | Item | Line1 | Line2 | City | State | Zip
1000 | Y234 | 111 B St. | Ste 1 | Miami | FL | 22222
Note, Ste 1 is not part of the address denoted in the OrderLine, it's actually part of the OrderHeader.
How can I write a query to return the data in the desired fashion? Any and all help is greatly appreciated!
Unfortunately, I can't think of a neat way to do this without being quite repetitive.
Assuming the OL aliases should have been CA:
SELECT OH.OrderNo, Item,
CASE WHEN OL.ShippingAddress IS NULL THEN OH.Line1 ELSE CA.Line1 END,
CASE WHEN OL.ShippingAddress IS NULL THEN OH.Line2 ELSE CA.Line2 END,
CASE WHEN OL.ShippingAddress IS NULL THEN OH.City ELSE CA.City END,
CASE WHEN OL.ShippingAddress IS NULL THEN OH.State ELSE CA.State END,
CASE WHEN OL.ShippingAddress IS NULL THEN OH.Zip ELSE CA.Zip END
FROM OrderHeader OH
JOIN OrderLine OL
ON OH.OrderNo = OL.OrderNo
LEFT JOIN CustomerAddress CA
ON OL.CustNum = CA.CustNum
AND OL.ShippingAddress = CA.ShippingAddress