Compare 2 views with different number of columns - mysql

I have 2 views with different number of columns. 1 of the views has been joined with another view that is why it has additional columns.
The first view has 113 records (View 2), while the updated view (View 1) has 130 columns. I would like to find out the number of records that are extra in View 1
.
View 1 View 2
A|B|C|D|E A|B|C
1 2 3 4 5 1 2 3
1 2 3 7 8
3 2 1 4 5 3 2 1
3 2 1 7 8
expected result :
1 2 3 7 8
3 2 1 7 8
Thanks.

You can get that extra records by using 'not in' or 'not exists' conditions
select * from view1 m where not exists (
select 1 from view2 u where (m.a=u.a and m.b=u.b and m.c=u.c)
You can change those conditions as per your requirement
With left join also will get the required result
select m.* from view1 m left join view2 u
(m.a=u.a and m.b=u.b and m.c=u.c)
where u.a is null and u.b is null and u.c is null

You shoul probably refactor your DB schema and data logic.
But just to resolve your weird requirements you can:
http://sqlfiddle.com/#!9/cf2c50/2
SELECT t.a, t.b, t.c, t.d, t.e
FROM (
SELECT v1.*, IF(#idx = concat(v1.a,v1.b,v1.c),1,0) `filter`,#idx := concat(v1.a,v1.b,v1.c)
FROM v1
INNER JOIN v2
ON v1.a=v2.a AND v1.b=v2.b AND v1.c=v2.c
ORDER BY v1.a,v1.b,v1.c
) t
WHERE t.`filter`=1;
It is not best example of query performance, but it should return expected result.

Related

SQL - Max value from a group by when creating a new field

I have a database with a table called BOOKINGS containing the following values
main-id place-id start-date end-date
1 1 2018-8-1 2018-8-8
2 2 2018-6-6 2018-6-9
3 3 2018-5-5 2018-5-8
4 4 2018-4-4 2018-4-5
5 5 2018-3-3 2018-3-10
5 1 2018-1-1 2018-1-6
4 2 2018-2-1 2018-2-10
3 3 2018-3-1 2018-3-28
2 4 2018-4-1 2018-4-6
1 5 2018-5-1 2018-5-15
1 3 2018-6-1 2018-8-8
1 4 2018-7-1 2018-7-6
1 1 2018-8-1 2018-8-18
1 2 2018-9-1 2018-9-3
1 5 2018-10-1 2018-10-6
2 5 2018-11-1 2018-11-5
2 3 2018-12-1 2018-12-25
2 2 2018-2-2 2018-2-19
2 4 2018-4-4 2018-4-9
2 1 2018-5-5 2018-5-23
What I need to do is for each main-id I need to find the largest total number of days for every place-id. Basically, I need to determine where each main-id has spend the most time.
This information must then be put into a view, so unfortunately I can't use temporary tables.
The query that gets me the closest is
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT `BOOKINGS`.`main-id`, `BOOKINGS`.`place-id`, SUM(DATEDIFF(`end-date`, `begin-date`)) AS `total`
FROM `BOOKINGS`
GROUP BY `BOOKINGS`.`main-id`,`RESERVATION`.`place-id`
Which yields:
main-id place-id total
1 1 24
1 2 18
1 5 5
2 1 2
2 2 20
2 4 9
3 1 68
3 2 24
3 3 30
4 1 5
4 2 10
4 4 1
5 1 19
5 2 4
5 5 7
What I need is then the max total for each distinct main-id:
main-id place-id total
1 1 24
2 2 20
3 1 68
4 2 10
5 1 19
I've dug through a large amount of similar posts that recommend things like self joins; however, due to the fact that I have to create the new field total using an aggregate function (SUM) and another function (DATEDIFF) rather than just querying an existing field, my attempts at implementing those solutions have been unsuccessful.
I am hoping that my query that got me close will only require a small modification to get the correct solution.
Having hyphen character - in column name (which is also minus operator) is a really bad idea. Do consider replacing it with underscore character _.
One possible way is to use Derived Tables. One Derived Table is used to determine the total on a group of main id and place id. Another Derived Table is used to get maximum value out of them based on main id. We can then join back to get only the row corresponding to the maximum value.
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT b1.main_id, b1.place_id, b1.total
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS b1
JOIN
(
SELECT dt.main_id, MAX(dt.total) AS max_total
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS dt
GROUP BY dt.main_id
) AS b2
ON b1.main_id = b2.main_id AND
b1.total = b2.max_total
MySQL 8+ solution would be utilizing the Row_Number() functionality:
CREATE VIEW `MOSTTIME` (`main-id`,`place-id`,`total`) AS
SELECT b.main_id, b.place_id, b.total
FROM
(
SELECT dt.main_id,
dt.place_id,
dt.total
ROW_NUMBER() OVER (PARTITION BY dt.main_id
ORDER BY dt.total DESC) AS row_num
FROM
(
SELECT `main-id` AS main_id,
`place-id` AS place_id,
SUM(DATEDIFF(`end-date`, `begin-date`)) AS total
FROM BOOKINGS
GROUP BY main_id, place_id
) AS dt
GROUP BY dt.main_id
) AS b
WHERE b.row_num = 1

Show Items even if 0 rows with group by

I'm trying to get the query below to show for each item for each store the amount of each of 4 items we have.
It works great, and I created the temporary table to try to increase speed but my problem is that if the table has no rows for a certain product that product does not show up at all.
I'd like to show all four products(prodNo) regardless of if there is actually any of rows for that specific store.
I researched this site and could not find something similar enough for me to figure it out.
CREATE TEMPORARY TABLE IF NOT EXISTS temp_invoice_dates AS
(
SELECT Invoice_detail.del_date,invoice_Detail.StoreNo,mast_stores.SDesc, invoice_Detail.ProdNo,sold_qty,retn_price,retn_qty,sold_price FROM Invoice_detail
LEFT JOIN mast_stores on invoice_detail.StoreNO=mast_stores.Snum
LEFT JOIN invoice on invoice_detail.Del_Date=invoice.Del_Date and invoice_detail.Invoice_No=invoice.Invoice_No
WHERE Cnum IN ('200','210') AND invoice_detail.Del_Date >= "2016-03-01" AND invoice_detail.Del_Date < "2016-04-01"
);
SELECT
temp_invoice_dates.StoreNo,
temp_invoice_dates.SDesc,
DATE_FORMAT(temp_invoice_dates.Del_Date,'%Y') as Year,
DATE_FORMAT(temp_invoice_dates.Del_Date,'%M') as Month,
temp_invoice_dates.ProdNo,
mast_items.IDesc,
SUM(sold_qty) as TotalIn,
SUM(retn_qty) as TotalOut,
ROUND(SUM((sold_qty*sold_price)-(retn_qty*retn_price)),2) as NetSales,
CONCAT(ROUND(SUM(retn_qty)/SUM(sold_qty),2)*100,'%') as StalePerc
FROM mast_Items
LEFT JOIN temp_invoice_dates on temp_invoice_dates.ProdNo=mast_items.Inum
WHERE mast_items.Inum in ('3502','3512','4162','4182')
GROUP BY temp_invoice_dates.StoreNo, ProdNo
ORDER BY temp_invoice_dates.StoreNo, ProdNo;
Drop table temp_invoice_dates;
Results are similar to:
StoreNo Product Count....
1 1 1
1 2 5
1 3 2
1 4 1
2 1 14
2 2 1
2 4 4
3 2 33
3 3 3
Where as I'd like it to be
StoreNo Product Count ....
1 1 1
1 2 5
1 3 2
1 4 1
2 1 14
2 2 1
2 3 0
2 4 4
3 1 0
3 2 33
3 3 3
3 4 0
Something like this should work.
SELECT sp.StoreNo, sp.ProdNo
, ...stuff...
, sp.IDesc, sp.SDesc
, ...more stuff...
FROM (
SELECT i.Inum AS ProdNo, s.Snum AS StoreNo
, i.IDesc, s.SDesc
FROM mast_Items AS i, mast_stores AS s
WHERE i.Inum IN ('3502','3512','4162','4182')
) AS sp
LEFT JOIN temp_invoice_dates AS tid
ON sp.ProdNo = tid.ProdNo
AND sp.StoreNo = tid.StoreNo
GROUP BY sp.StoreNo, sp.ProdNo
ORDER BY sp.StoreNo, sp.ProdNo
;
Normally I recommend against cross joins (as seen in the subquery) but in this case it is exactly what is needed. If the query is slow, you can instead insert the subquery results into a temp table beforehand, index that, and then use the temp table in place of the subquery.
(Edit: should use sp fields when available for grouping and results)

SQL: JOIN tables with the result having unique values on one of the columns?

I would like to join two tables but to specify that the result should have unique values on one of the columns.
http://sqlfiddle.com/#!2/70ded/4
Instead of
URLID DOMAINID
13 5
9 3
10 3
11 4
12 4
6 2
7 2
8 2
1 1
2 1
3 1
4 1
5 1
I would like to get:
URLID DOMAINID
13 5
9 3
11 4
6 2
1 1
Is it possible doing it and by that creating a faster query?
Your query will not be faster, because you have to remove the duplicates. Here is a MySQL way:
select urlID, domainID
from (<your query>) as t
group by domainID
This uses a MySQL mis(feature) called hidden columns. In most databases, you would use:
select min(urlID), domainID
from (<your query>) as t
group by domainID
How about this? I just applied an aggregate to the urlid and added a group by:
SELECT min(urlid) urlid, domain_stack.domainid
FROM domain_stack
INNER JOIN url_stack
ON url_stack.domainid = domain_stack.domainid
group by domain_stack.domainid
order by domain_stack.domainid desc
See SQL Fiddle with Demo
SELECT urlid,domain_stack.domainid
FROM domain_stack
INNER JOIN url_stack
ON url_stack.domainid = domain_stack.domainid
GROUP BY domainid

MYSQL select query using count (*)

i have a problem concerning a select query in MYSQL
i have two different tables and i want to obtain a certain result
i used COUNT method which gave me only the results (>=1)
But in reality , i want to use all counts with zero included how to do it?
My query is:
SELECT
first.subscriber_id,
second.tag_id,
COUNT(*)
FROM
content_hits first
JOIN content_tag second ON first.content_id=second.content_id
GROUP BY
second.Tag_id,first.Subscriber_id<br>
First table:Content_hits
CONTENT_ID SUBSCRIBER_ID
30 1
10 10
34 4
32 2
40 3
28 3
30 6
31 8
12 3
Second table:Content_tag
CONTENT_ID TAG_ID
1 1
2 1
3 1
4 1
5 1
6 1
7 1
8 1
9 1
10 1
11 2
12 2
13 2
14 2
Result but incomplete For example:Subsrciber6 for tag_id=1 should have a count(*)=0
subscriber_id tag_id COUNT(*)
1 1 4
2 1 7
3 1 2
4 1 1
5 1 3
7 1 2
8 1 1
9 1 1
10 1 3
1 2 2
2 2 3
3 2 2
Now that you have further elaborated on what you actually want to achieve, it can be seen that the problem is much more complex. You actually want all combinations of subscriber_id and tag_id, and then count the number of actual entries in the joined table product. whew. So here goes the SQL:
SELECT combinations.tag_id,
combinations.subscriber_id,
-- correlated subquery to count the actual hits by tag/subscriber when joining
-- the two tables using content_id
(SELECT count(*)
FROM content_hits AS h
JOIN content_tag AS t ON h.content_id = t.content_id
WHERE h.subscriber_id = combinations.subscriber_id
AND t.tag_id = combinations.tag_id) as cnt
-- Create all combinations of tag/subscribers first, before counting anything
-- This will be necessary to have "zero-counts" for any combination of
-- tag/subscriber
FROM (
SELECT DISTINCT tag_id, subscriber_id
FROM content_tag
CROSS JOIN content_hits
) AS combinations
Not sure, but is this what you want?
SELECT first.subscriber_id, second.tag_id, COUNT(*) AS c
FROM content_hits first JOIN content_tag second ON first.content_id=second.content_id
GROUP BY second.Tag_id,first.Subscriber_id HAVING c = 0

Complicated Crosstab Query Question

I have the following 2 tables:
1) Companies
ID CompanyName Abbreviation Notes
1 CompanyA CA ...
2 CompanyB CB ...
3 CompanyC CC ...
2) PlannedDeployments
ID CompanyID TypeID DepDate NumDeployed
1 1 2 09/2010 5
2 1 2 10/2010 5
3 1 3 09/2010 3
4 1 3 10/2010 3
5 1 4 10/2010 4
6 2 2 12/2010 10
7 2 4 10/2010 1
8 3 2 11/2010 6
Note that TypeID is a number between 1 and 5 describing what type of person is being deployed. For the purposes of this query, I'm interested in Type2 employees for each company and then the sum of Types 3 & 4 for each date. What I eventually want to end up with is a crosstab that looks like the following:
Crosstab
Date/Company CompanyA CompanyB CompanyC SumOfTypes3and4
09/2010 5 3
10/2010 5 8
11/2010 6
12/2010 10
The problem is that final column - the sum of Type 3 and Type 4 employees. The current crosstab that I have includes everything except that sum column and looks like the following:
TRANSFORM Sum(PlannedDeployments.NumDeployed) AS ["NumDeployed"]
SELECT PlannedDeployments.DepDate
FROM PlannedDeployments LEFT JOIN Companies ON Companies.ID=PlannedDeployments.CompanyID
WHERE PlannedDeployments.TypeID=2 AND (PlannedDeployments.DepDate Between FormFieldValue("Form", "Control") AND FormFieldValue("Form", "Control"))
GROUP BY PlannedDeployments.DepDate
PIVOT Companies.CompanyName;
The second part of that WHERE clause is just limiting the data by some form controls. Anyway - I'm having a lot of trouble getting that final column. Anyone have any ideas?
Edit: Building on the solution provided by Remou below, here's what the final query ended up looking like:
TRANSFORM Sum(PlannedDeployments.NumDeployed) AS ["NumDeployed"]
SELECT PlannedDeployments.DepDate, q.SumOfNumDeployed
FROM (SELECT PlannedDeployments.DepDate, Sum(PlannedDeployments.NumDeployed) AS SumOfNumDeployed
FROM PlannedDeployments
WHERE (((PlannedDeployments.[TypeID]) In (3,4)))
GROUP BY PlannedDeployments.DepDate) AS q
RIGHT JOIN (PlannedDeployments
INNER JOIN Companies ON PlannedDeployments.CompanyID = Companies.ID)
ON q.DepDate = PlannedDeployments.DepDate
WHERE PlannedDeployments.TypeID=2
AND (PlannedDeployments.DepDate Between FormFieldValue("Form", "Control")
AND FormFieldValue("Form", "Control"))
GROUP BY PlannedDeployments.DepDate, q.SumOfNumDeployed
PIVOT Companies.CompanyName;
You can use a subquery:
TRANSFORM Sum(PlannedDeployments.NumDeployed) AS ["NumDeployed"]
SELECT PlannedDeployments.DepDate, Sum(q.SumOfNumDeployed) AS SumOfSumOfNumDeployed
FROM (SELECT PlannedDeployments.DepDate, Sum(PlannedDeployments.NumDeployed) AS SumOfNumDeployed
FROM PlannedDeployments
WHERE (((PlannedDeployments.[TypeID]) In (3,4)))
GROUP BY PlannedDeployments.DepDate) AS q
RIGHT JOIN (PlannedDeployments
INNER JOIN Companies ON PlannedDeployments.CompanyID = Companies.ID)
ON q.DepDate = PlannedDeployments.DepDate
WHERE PlannedDeployments.TypeID=2
AND (PlannedDeployments.DepDate Between FormFieldValue("Form", "Control")
AND FormFieldValue("Form", "Control"))
GROUP BY PlannedDeployments.DepDate
PIVOT Companies.CompanyName;